DIRECTORY AtomButtons, AtomButtonsTypes, CodeTimer, Feedback, FS, GraphicsButton, Imager, IO, Menus, PopUpSelection, Rope, SlackProcess, SV2d, SV3d, SVDraw, 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, 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]; BuildRadiusLine[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["Merge", LIST[LIST[$Merge]], -1, FALSE, NIL, ConfirmMerge]], [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] = { 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[]; colorMenu: AtomButtons.ButtonLineEntry _ [popUpButton["Color", LIST [ [LIST [$StrokeColorFromColorTool], "FromColorTool [G]", "Make selected strokes have the color in the ColorTool"], [LIST [$PrintStrokeColor], "ShowStrokeColor [G]", "Print stroke color of selected stroke"], [LIST [$StrokeColorToColorTool], "ToColorTool [G]", "Send the stroke color of the selected stroke to the ColorTool"], [LIST [$StrokeColorNone], "none [G]", "Make selected strokes have no color (invisible)"], [LIST [$StrokeColorFollowColorTool], "FollowColorTool [G]", "Selected stroke colors will track the ColorTool. Any mouse click terminates FollowColorTool"], [LIST [$StrokeColorGray, NEW[REAL_1.0]], "white [G]", "Make selected strokes have color white"], [LIST [$StrokeColorFromSelectedName], "FromSelectedName [GT]", "Make selected strokes have the color named in the Tioga selection (e.g. vivid green)"], [LIST [$SelectMatchingStrokeCNS], "MatchSelectedName [T]", "Select strokes whose color match the name in the Tioga selection (e.g. vivid green)"], [LIST [$StrokeColorGray, NEW[REAL_0.0]], "black [G]", "Make selected strokes have color black"], [LIST [$StrokeColorFromSelectedRGB], "FromSelectedRGB [GT]", "Make selected strokes have the RGB specified in the Tioga selection (e.g. r: 0.5 g: 0.9 b: 0.67)"], [LIST [$SelectMatchingStrokeRGB], "MatchSelectedRGB [T]", "Select strokes whose color match the RGB in the Tioga selection (e.g. r: 0.5 g: 0.9 b: 0.67)"], [LIST [$StrokeColorGray], "gray [G]", "Make selected strokes have color gray"], noOpChoice, [LIST [$ShowDefaultStrokeColor], "ShowDefault", "Print default stroke color"], [LIST [$SetDefaultStrokeColor], "MakeDefault [G]", "Set the default stroke color from the currently selected stroke"] ], -1, FALSE, popUpFont, NIL, quickClickMode]]; fillMenu: AtomButtons.ButtonLineEntry _ [popUpButton["Fill", LIST [ [LIST [$AreaColorFromColorTool], "FromColorTool [G]", "Make selected objects have the fill color in the ColorTool"], [LIST [$PrintAreaColor], "ShowFillColor [G]", "Print fill color of selected object"], [LIST [$AreaColorToColorTool], "ToColorTool [G]", "Send the fill color of the selected object to the ColorTool"], [LIST [$AreaColorNone], "none [G]", "Make selected objects have no fill color"], [LIST [$AreaColorFollowColorTool], "FollowColorTool [G]", "Selected fill colors will track the ColorTool. Any mouse click terminates FollowColorTool"], [LIST [$AreaColorGray, NEW[REAL_1.0]], "white [G]", "Make selected objects have fill color white"], [LIST [$AreaColorFromSelectedName], "FromSelectedName [GT]", "Make selected objects have the fill color named in the Tioga selection (e.g. vivid green)"], [LIST [$SelectMatchingAreaCNS], "MatchSelectedName [T]", "Select objects whose fill color matches the name in the Tioga selection (e.g. vivid green)"], [LIST [$AreaColorGray, NEW[REAL_0.0]], "black [G]", "Make selected objects have fill color black"], [LIST [$AreaColorFromSelectedRGB], "FromSelectedRGB [GT]", "Make selected objects have the fill RGB specified in the Tioga selection (e.g. r: 0.5 g: 0.9 b: 0.67)"], [LIST [$SelectMatchingAreaRGB], "MatchSelectedRGB [T]", "Select objects whose fill color match the RGB in the Tioga selection (e.g. r: 0.5 g: 0.9 b: 0.67)"], [LIST [$AreaColorGray, NEW[REAL_0.5]], "gray [G]", "Make selected objects have fill color gray"], noOpChoice, [LIST [$ShowDefaultFillColor], "ShowDefault", "Print default fill color"], [LIST [$SetDefaultFillColor], "MakeDefault [G]", "Set the default fill color from the currently selected object"] ], -1, FALSE, popUpFont, NIL, quickClickMode]]; selectMenu: AtomButtons.ButtonLineEntry _ [popUpButton["Select", LIST [ [LIST [$CycleSelection, $Forward], "CycleSelection", "Select a different object that is near the selected one."], noOpChoice, [LIST [$CycleSelection, $Backward], "UnCycleSelection", "Select a different object that is near the selected one."], [LIST [$BlockSelectNew], "New [G]", "Select all objects within the bounding box of the current selection"], [LIST [$BlockSelectNewAndDelete], "NewAndDelete [G]", "Select all objects within the bounding block of the current selection and delete the original selection"], [LIST [$BlockSelectExtend], "Extend [G]", "Add all objects within the bounding block of the current selection to the current selection"], [LIST [$SelectAll], "All (^d)", "Select every object in the scene"], noOpChoice, noOpChoice ], -1, FALSE, popUpFont, NIL, quickClickMode]]; 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[ colorMenu, fillMenu, 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[$InitStandardAzimuths], 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[$InitStandardSlopes], 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[$InitStandardSlopeLines], 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[$InitStandardSlopePlanes], svData]; svData.height _ svData.height + entryHeight; }; BuildRadiusLine: PROC [svData: SVData] = { buttonHandle: AtomButtons.SortedButtonHandle; nextX: NAT _ AtomButtons.BuildButtonLine[svData.outer, 0, svData.height, svData, SVUserInput.EventNotify, LIST[ [button["Radius:", LIST[LIST[$RadiusPrompt]] ]], [button["Get!", LIST[LIST[$GetRadius]], getScalarColumn ]], [button["Add!", LIST[LIST[$AddRadius]] ]], [button["Delete!", LIST[LIST[$DeleteRadius]] ]] ]]; buttonHandle _ AtomButtons.CreateSortedButtonViewer[svData.outer, scalarButtonColumn, svData.height]; svData.hitTest.radiusHandle _ buttonHandle; SVEvent.StandardRadii[LIST[$InitStandardRadii], 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]], [button["RadiusValue:", LIST[LIST[$MeasureRadiusHit]] ]], [text["0.0", RadiusViewInSVData, 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 ConfirmMerge: PROC [clientData: REF ANY] = { svData: SVData _ NARROW[clientData]; filename: Rope.ROPE _ ViewerTools.GetSelectionContents[]; Feedback.AppendHerald[svData.feedback, Rope.Cat["Confirm addition of file ", filename, " to the current scene."], oneLiner]; }; 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]], ["RayCastColor", LIST [$RayCastColor]], ["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.RayCast[LIST[$RayCastColor], svData]; =3 => SVEvent.StopRays[LIST[$StopRays], svData]; =4 => 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] }; ShowColorsInit: AtomButtonsTypes.InitTwoStateProc = { svData: SVData _ NARROW[clientData]; AtomButtons.SetBinaryState[twoState, FALSE]; svData.refresh.showColors _ twoState; }; GravityExtentInSVData: AtomButtonsTypes.UpdateGraphicsButtonProc = { svData: SVData _ NARROW[clientData]; svData.hitTest.gravityExtentButton _ stateInfo; }; 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]; }; GravityButtonInit: AtomButtons.InitTwoStateProc = { svData: SVData _ NARROW[clientData]; svData.hitTest.gravButton _ twoState; }; MidpointsButtonInit: AtomButtons.InitTwoStateProc = { svData: SVData _ NARROW[clientData]; svData.hitTest.midpointButton _ twoState; }; HeuristicsButtonInit: AtomButtons.InitTwoStateProc = { svData: SVData _ NARROW[clientData]; svData.hitTest.heuristicsButton _ twoState; }; AzimuthViewInSVData: AtomButtons.InitButtonProc = { svData: SVData _ NARROW[clientData]; svData.measure.azimuthView _ button; }; SlopeViewInSVData: AtomButtons.InitButtonProc = { svData: SVData _ NARROW[clientData]; svData.measure.slopeView _ button; }; RadiusViewInSVData: AtomButtons.InitButtonProc = { svData: SVData _ NARROW[clientData]; svData.measure.radiusView _ button; }; 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; }; ViewStyleInSVData: 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; }; Init: PROC = { boldFont _ VFonts.EstablishFont[family: "Helvetica", size: 10, bold: TRUE, italic: FALSE, defaultOnFailure: TRUE]; popUpFont _ VFonts.EstablishFont[family: "Helvetica", size: 10, bold: FALSE, italic: TRUE, defaultOnFailure: TRUE]; }; Init[]; END. SVMenusImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last edited by Bier on January 28, 1987 11:16:05 pm PST Contents: Routines for building the control panel on each solid viewer. Non-destructive (copies the menu names). Build All of the Control Panel Menus Clear, Restore, Get, Store, Save, Split, Erase, Interpress, Script, CastRays, Revive! Space down from the top of the viewer. This section implements a set of buttons, text windows, and options listers in this format: Draw: BBox BSphere Scene Coords Point Cross Color B&W Dither CoordsMode File Line Menus: Master Line Menus: QueuePopUpMenuAction["SVCastRays", menu, svData, mouseButton#blue]; IF mouseButton = blue THEN { -- black and white only } ELSE { exists _ SVFiles.FileExists[aisFileRope] OR SVFiles.FileExists[redRope] OR SVFiles.FileExists[greenRope] OR SVFiles.FileExists[blueRope]; rope _ IO.PutFR["Confirm raycast to %g [-red, -green, -blue, plain].ais", [rope[SVFiles.FilenameMinusExtension[aisFileRope]]]]; IF exists THEN rope _ Rope.Concat[rope, " [Old Files]"] ELSE rope _ Rope.Concat[rope, " [New Files]"]; }; Style Line Menus: Gravity Line Menus: Feedback Line Wiring Up Buttons to the Container: DoubleBufferInSVData: AtomButtons.InitButtonProc = { svData: SVData _ NARROW[clientData]; svData.textSection.doubleBuffer _ button; Buttons.SetDisplayStyle[svData.textSection.doubleBuffer, $WhiteOnBlack]; }; ΚN˜J˜Icodešœ™Kšœ Οmœ1™Kš œžœžœžœžœ˜DKš œžœžœžœžœ˜DKšœ$˜$Kšœžœžœ ˜&Kšœžœžœ ˜&K˜K˜—šœgžœ˜lKšœžœ žœžœ ˜AKšœ#žœ žœžœ ˜EKšœ!˜!K˜—šœxžœ˜}Kšœžœžœ˜2K˜K˜—Lšœ:˜:L˜L˜—šŸœžœ˜.Lšœ\™\LšŸœC™GKšœžœ˜šœ-˜-šœžœ˜ KšœžœH˜MKšœžœH˜MKšœžœH˜MK˜Kšœžœ]˜bKšœžœ]˜bKšœžœ]˜bK˜KšœžœN˜SKšœžœ]˜bKšœžœQ˜VK˜Kšœžœd˜iKšœžœ-˜2Kšœžœj˜oK˜KšœžœC˜HKšœžœU˜ZKšœžœX˜]K˜KšœžœH˜MKšœžœH˜MKšœžœG˜LK˜—Kšœžœžœ˜K˜—šœfžœ˜kKšœžœžœ˜.Kšœžœžœ˜4Kšœ ˜ K˜—šœgžœ˜lKšœžœ žœžœ ˜AKšœžœ žœžœ ˜>K˜K˜—Lšœ:˜:Lšœ ˜ L˜—šŸœžœ˜-Kšœžœ˜Kšœžœ(˜Kšœžœ‘ œ‘œ˜BKšœžœ ‘œ˜AKšœžœ/‘,œ˜cKšœžœ-‘)œ˜^Kšœžœ3‘1œ˜lKšœžœ)‘œ˜NK˜—Kšœžœ žœ˜,K˜K˜—šœfžœ˜kK˜ K˜ Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœžœžœ˜IKšœžœžœ˜2Kšœ6˜6Kš œžœžœžœžœžœ˜RK˜K˜—Lšœ:˜:K˜K˜—šŸœžœ˜+Kšœžœ˜Kšœ!˜!šœ_˜_Kšœ˜Kšœ$˜$Kšœ,˜,Kšœžœ žœ˜:Kšœ žœ/˜@Kšœ˜—Kšœ-˜-K˜Kšœ-˜-šœ$˜$šœSžœ˜XKšœΟb œ˜—Kšœ˜K˜—šœ+˜+Kšœ˜Kšœ˜Kšœ˜Kšœ ,˜3Kšœ˜Kšœ˜šœ žœ˜Kšœžœ"˜'Kšœžœ'˜,Kšœžœ%˜*—Kšœ$˜$Kšœ"˜"Kšœ žœH˜WKšœ!˜!Kšœ˜K˜—šœ$˜$šœUžœ˜ZKšœžœžœ˜EKšœžœžœ˜LKšœžœK˜g—Kšœ˜K˜—Kšœ,˜,K˜K˜—šŸœžœ˜-Kšœžœ˜KšœžœE˜WKšœžœ$˜8K˜šœfžœ˜kKš œžœžœžœžœžœ˜]Kšœžœžœ˜+Kšœ3˜3K˜K˜—Lšœ:˜:Lšœ ˜L˜—šŸœžœ˜+Kšœ-˜-šœžœ_žœ˜oKšœžœžœ˜2Kšœžœžœ#˜Kšœ,˜,˜K˜——šŸœžœ˜)Kšœ-˜-šœžœ_žœ˜oKšœžœžœ˜.Kšœžœžœ!˜:Kšœžœžœ˜)Kšœžœžœ˜.K˜—Kšœe˜eKšœ*˜*Kšœžœ˜:Kšœ,˜,K˜K˜—šŸœžœ˜-Kšœ-˜-šœžœ_žœ˜oKšœžœžœ˜1Kšœžœžœ%˜>Kšœžœžœ ˜9Kšœžœžœ˜-Kšœžœžœ˜2K˜—Kšœe˜eKšœ.˜.Kšœžœ#˜BKšœ,˜,K˜K˜—šŸœžœ˜.Kšœ-˜-šœžœ_žœ˜oKšœžœžœ˜3Kšœžœžœ&˜?Kšœžœžœ ˜9Kšœžœžœ˜.Kšœžœžœ˜3K˜—Kšœe˜eKšœ/˜/Kšœžœ$˜DKšœ,˜,K˜K˜—šŸœžœ˜*Kšœ-˜-šœžœ_žœ˜oKšœžœžœ˜0Kšœžœžœ"˜;Kšœžœžœ˜*Kšœžœžœ˜/K˜—Kšœe˜eKšœ+˜+Kšœžœ˜8Kšœ,˜,K˜K˜—šŸœžœ˜+šœžœ`žœ˜oKšœžœžœ˜;Kšœ4˜4Kšœžœžœ˜7Kšœ2˜2Kšœžœžœ˜9Kšœ2˜2K˜—Kšœ,˜,K˜K˜—šŸœžœ˜,šœžœ`žœ˜oKšœΆ˜ΆK˜—Kšœ,˜,K˜K˜—K™K™š Ÿ œžœžœžœžœ˜3Jšœžœ ˜$Jšœ˜Jšœ žœ˜Jšœžœ˜ Jšœ ˜ Jšžœžœ"˜/Jšžœ%˜)Jšœ7˜7Jšœ˜J˜—š Ÿ œžœžœžœžœ˜3Jšœžœ ˜$Jšœ˜Jšœžœ˜ Jšœ ˜ JšžœžœK˜XJšžœ[˜_Jšœ ˜—š Ÿ œžœžœžœžœ˜2Jšœžœ ˜$Jšœ˜Jšœžœ˜ Jšœ žœ˜Jšœ(˜(Jšžœžœžœ;˜Sšžœ˜Jšœžœ:˜CJšœ˜Jšœ˜—Jšœ1˜1Jšœ˜—š Ÿ œžœžœžœžœ˜3Jšœžœ ˜$Jšœžœ˜9Jšœ˜Jšœžœ&˜8Jšœžœ˜Jšœžœ˜ Jšœ žœžœ˜Jšœ žœ˜J˜šžœžœ˜"JšœI˜IJšœ ˜ Jšžœ˜J˜—Jšœ-˜-šœžœ˜*šœžœ žœžœ˜*J•StartOfExpansion[]šœV˜VJšœ žœ˜Jšžœ˜ J˜—Jšœ˜—J˜Jšœ&˜&Jšžœžœžœ:˜RJšžœžœ;˜IJšœ7˜7Jšœ˜—š Ÿ œžœžœžœžœ˜1Jšœžœ ˜$Jšœžœ˜9Jšœ˜Jšœžœ&˜8Jšœžœ˜Jšœ žœžœ˜Jšœžœ˜ J˜šžœžœ˜"JšœI˜IJšœ ˜ Jšžœ˜Jšœ˜—Jšœ-˜-J˜šœžœ˜*šœžœ žœžœ˜*J–[]šœT˜TJšœ žœ˜Jšžœ˜ J˜—Jšœ˜—Jšžœžœ žœžœ˜Jšœ ˜ Jšžœžœf˜sJšžœR˜VJšœ ˜J˜—šΠbn œžœžœžœ˜,Kšœžœ ˜$Kšœžœ&˜9Kšœ|˜|Kšœ˜K˜J˜—K™šŸ œ˜Kšœžœ ˜$Kšœžœžœ˜šœžœ˜ Kšœ žœ˜!K˜—Kšœ?˜?K˜—š£ œ˜Kšœžœ ˜$Kšœžœžœ˜šœžœ˜ Kšœžœ˜+Kšœžœ˜/Kšœžœ˜/Kšœžœ˜!Kšœžœ˜1Kšœžœ˜#Kšœžœ˜1Kšœžœ˜+Kšœžœ˜%Kšœžœ˜.Kšœžœ˜.Kšœžœ˜%K˜—Kšœ>˜>K˜—š£ œ˜!Kšœžœ ˜$šœžœžœžœ˜%Kšœ žœ ˜Kšœžœ˜'Kšœ žœ˜Kšœ žœ ˜K˜—Kšœ žœžœžœ˜5KšœžœA˜Kšžœž˜Kšœžœ˜ Kšœžœ˜.Kšœžœ˜3Kšœžœ˜0Kšœžœ˜(Kšžœžœ˜—KšœC™CK˜—š£ œ˜Kšœžœ ˜$šœžœžœžœ˜%Kšœžœ˜,Kšœžœ˜2Kšœžœ˜.Kšœžœ˜4Kšœžœ˜3K˜—Kšœ žœžœžœ˜5Kšœžœ=˜Gšžœž˜Kšœžœ˜ KšœJ˜JKšœN˜NKšœK˜KKšœN˜NKšœN˜NKšžœžœ˜—K˜—š Ÿœžœžœžœžœ˜5Jšœžœ ˜$Jšœžœ˜ Jšœžœ˜JšœžœH˜ZJšœžœJ˜^JšœžœI˜\Jšœ žœ˜šžœžœ ™4Jšœ)˜)Jšœžœ6˜?Jšžœžœ(˜6Jšžœ)˜-Jšœ™—šžœ™Jšœ)žœžœžœ™‰Jšœžœv™Jšžœžœ)™7Jšžœ*™.Jšœ™—Jšœ7˜7Jšœ˜J˜—š£ œ˜!Kšœžœ ˜$Kšœ)˜)Kšœ6˜6Kšœ)˜)Kšœ!žœ˜'Kšœžœžœ˜Kš žœžœtžœ žœžœ˜ΊK˜K˜—K™K™K™šŸœ'˜5Kšœžœ ˜$Kšœ%žœ˜,Kšœ%˜%K˜—K™K™šŸœ/˜DKšœžœ ˜$Kšœ/˜/K˜—š Ÿœžœ"žœžœžœžœ˜mK˜Kšœžœ ˜,Kšœžœ˜Kšœ2˜2Kšœ˜Kšœ!˜!K˜K˜—šŸœ"˜3Kšœžœ ˜$Kšœ%˜%K˜—šŸœ"˜5Kšœžœ ˜$Kšœ)˜)K˜—šŸœ"˜6Kšœžœ ˜$Kšœ+˜+K˜K˜K˜—šŸœ ˜3Kšœžœ ˜$Kšœ$˜$K˜K˜—šŸœ ˜1Kšœžœ ˜$Kšœ"˜"K˜K˜—šŸœ ˜2Kšœžœ ˜$Kšœ#˜#K˜K˜K˜—K™K™ šŸœ%˜9Kšœžœ ˜$KšœH˜HKšœ˜K˜—K™K™#K˜šŸœ ˜2Kšœžœ ˜$Kšœ'˜'K˜K˜—šŸœ ˜1Kšœžœ ˜$Kšœ&˜&K˜K˜—šŸœ ˜0Kšœžœ ˜$Kšœ%˜%K˜K˜—šŸœ ˜/Kšœžœ ˜$Kšœ ˜ K˜K˜—šŸœ ™4Kšœžœ ™$Kšœ)™)LšœH™HK™K™—šŸœžœ˜KšœEžœ žœžœ˜rKšœFžœ žœžœ˜sK˜K˜—Kšœ˜K˜Kšžœ˜K˜J˜—…—tJ–(