File: SVWindowImpl.mesa
Author: Eric Bier on July 2, 1983 5:03 pm
Copyright © 1984 by Xerox Corporation. All rights reserved.
Last edited by Bier on July 12, 1987 1:54:53 pm PDT
Contents: Code to create a solid viewer. Calls SVViewerTool to make the container and adds menus at the top. The 3D part of the solid viewer is a new viewer of class $SolidWindow. The paint proc for a $SolidWindow is defined herein.
DIRECTORY
BufferedRefresh, CoordSys, Cursors, Feedback, FileNames, FunctionCache, FS, Icons, Imager, Matrix3d, Menus, Rope, SlackProcess, SV2d, SV3d, SVAlign, SVBoundBox, SVCaret, SVDrawMonitor, SVGravity, SVInterfaceTypes, SVMeasure, SVMenus, SVModelTypes, SVMouseEvent, SVRefresh, SVScene, SVSceneTypes, SVSessionLog, SVState, SVTransforms, SVUserInput, SVVector3d, SVViewerTool, SVViewerTools, SVWindow, Terminal, TIPUser, ViewerClasses, ViewerOps;
SVWindowImpl: CEDAR PROGRAM
IMPORTS BufferedRefresh, CoordSys, Cursors, Feedback, FileNames, FunctionCache, FS, Icons, Imager, Matrix3d, Menus, Rope, SlackProcess, SVAlign, SVBoundBox, SVCaret, SVGravity, SVMeasure, SVMenus, SVMouseEvent, SVRefresh, SVScene, SVSessionLog, SVState, SVTransforms, SVUserInput, SVVector3d, SVViewerTool, SVViewerTools, Terminal, TIPUser, ViewerOps
EXPORTS SVWindow
SHARES ViewerClasses =
BEGIN
Camera: TYPE = SVModelTypes.Camera;
CoordSystem: TYPE = SVModelTypes.CoordSystem;
EditToolData: TYPE = SVInterfaceTypes.EditToolData;
FileCamera: TYPE = SVSceneTypes.FileCamera;
Filters: TYPE = SVInterfaceTypes.Filters;
FiltersObj: TYPE = SVInterfaceTypes.FiltersObj;
ForegroundParts: TYPE = SVWindow.ForegroundParts;
Matrix4by4: TYPE = SV3d.Matrix4by4;
MouseButton: TYPE = Menus.MouseButton;
Plane: TYPE = SV3d.Plane;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = SV3d.Point3d;
Scene: TYPE = SVSceneTypes.Scene;
SkitterObj: TYPE = SVInterfaceTypes.SkitterObj;
Viewer: TYPE = ViewerClasses.Viewer;
SVData: TYPE = REF SVDataObj;
SVDataObj: TYPE = SVInterfaceTypes.SVDataObj;
PlaceOrigin: PROC [viewer: Viewer] = {
viewer is the viewerPicture
Find the center of the solid window in solid window coordinates.
originX, originY: REAL;
transMat: Matrix4by4;
svData: SVData ← NARROW[viewer.data];
screenCS: CoordSystem;
camera: Camera ← svData.camera;
screenCS ← camera.screenCS;
originX ← viewer.cw;-- convert window width to real
originY ← viewer.ch;-- convert window height to real
originX ← originX/2.0;-- find the midpoint in window coords
originY ← originY/2.0;
transMat ← Matrix3d.MakeTranslateMat[-originX,-originY,0];
SVTransforms.AbsTransfScreen[screenCS, transMat];
BufferedRefresh.FitSandwichToScreen[svData.refresh.sandwich, viewer.cw, viewer.ch];
}; -- end of PlaceOrigin
SVActionAreaPaint: PROC [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] RETURNS [quit: BOOLFALSE] = {
ViewerClasses.PaintProc
whatChanged is a SVData. self is a ViewerPicture.
PaintEntireViewer: PROC = {
PlaceOrigin[self];
RestoreScreenAndInvariants[paintAction: $PaintEntireScene, svData: svData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
};
svData: SVData;
IF whatChanged = NIL THEN { --we are being called by Window Manager
svData ← NARROW[self.data];
PlaceOrigin[self];
Imager.SetFont[context, svData.editToolData.screenFont];
RestoreScreenAndInvariants[paintAction: $ViewersPaintEntireScene, svData: svData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
}
ELSE {
svData ← NARROW[whatChanged];
Imager.SetFont[context, svData.editToolData.screenFont];
SELECT svData.refresh.paintAction FROM
$PaintEntireViewer => PaintEntireViewer[];
$CallAProc => {
paintProc: SVInterfaceTypes.DisplayContextProc ← svData.refresh.paintProc;
paintProc[context];
};
ENDCASE => SVRefresh.ActionAreaPaint[context, svData.refresh.paintAction, svData];
};
};
RestoreScreenAndInvariants: PUBLIC PROC [paintAction: ATOM, svData: SVData, remake: ForegroundParts ← triggerBag, backgndOK: BOOLFALSE, edited: BOOLTRUE, okToClearFeedback: BOOLTRUE] = {
Rebuild bags as requested.
SELECT remake FROM
none => NULL;
triggerBag => {
SVAlign.SetStaticBags[svData];
BufferedRefresh.SetLayerOK[svData.refresh.sandwich, $Foreground, FALSE];
};
alignBag => {
SVAlign.FlushAlignBag[svData.hitTest.alignBag];
SVAlign.FillStaticAlignBag[svData.hitTest.triggerBag, svData.hitTest.sceneBag, svData.hitTest, NOT SVState.GetShowAlignments[svData], SVState.GetMidpoints[svData], svData.hitTest.alignBag];
BufferedRefresh.SetLayerOK[svData.refresh.sandwich, $Foreground, FALSE];
};
bitMap => {
BufferedRefresh.SetLayerOK[svData.refresh.sandwich, $Foreground, FALSE];
};
sceneBag => {
SVAlign.FlushTriggerBag[svData.hitTest.sceneBag];
SVAlign.FillStaticSceneBag[svData.scene, svData.hitTest.sceneBag];
};
ENDCASE => ERROR;
Refresh the screen.
svData.refresh.paintAction ← paintAction;
ViewerOps.PaintViewer[
viewer: svData.actionArea,
hint: client,
whatChanged: svData,
clearClient: FALSE]
};
RawPaint: PUBLIC PROC [paintProc: SVInterfaceTypes.DisplayContextProc, svData: SVData] = {
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
svData.refresh.paintProc ← paintProc;
svData.refresh.paintAction ← $CallAProc;
ViewerOps.PaintViewer[viewer: svData.actionArea,
hint: client,
whatChanged: svData,
clearClient: FALSE];
};
CreateWindow: PUBLIC PROC [editToolData: EditToolData, scene: Scene, iconic: BOOL, paint: BOOL, workingDirectory: Rope.ROPE] RETURNS [svData: SVData, viewerPicture: Viewer] = {
parent is the EditTool
Create the Container and the top menu which looks like this:
Clear, Reset, Get, Store, Save, Split, Erase, Raycast, Stop, Aray, Press, Extend, Move
#BBox #Scene #Coords #Point #Cross #Color #B&W Coords
screenCS, worldCS: CoordSystem;
success: BOOL;
fileCamera: FileCamera;
iconFileName: Rope.ROPE;
windowMenu: Menus.Menu;
svData ← NEW[SVDataObj];
svData.currentWDir ← workingDirectory;
svData.originalWDir ← originalWDir; --global
windowMenu ← Menus.CreateMenu[0];
svData.editToolData ← NARROW[editToolData];
svData.scene ← scene;
iconFileName ← Rope.Concat[editToolData.originalWorkingDirectory, "SolidViews.icons"];
Construct the outer container.
svData.outer ← SVViewerTool.Create[
info: [
name: Rope.Concat["Solid Scene: ", svData.scene.name],
menu: windowMenu,
data: svData,
iconic: TRUE,
column: left,
scrollable: FALSE,
icon: Icons.NewIconFromFile[iconFileName, 0]
],
paint: FALSE];
Find the current scene.
screenCS ← CoordSys.CreateRoot["SCREEN"];
IF scene.cameraOrder # NIL THEN [fileCamera, ----] ← SVScene.FindFileCameraFromName[scene.cameraOrder.first,
svData.scene]
ELSE {
[fileCamera, success] ← SVScene.FindFileCameraFromName["Front",
svData.scene];
IF NOT success THEN ERROR;
};
worldCS ← scene.coordSysRoot;
svData.slackHandle ← SlackProcess.Create[queueSize: 50, logSize: 50, optimizeProc: OptimizeQueue, loggingProc: SVSessionLog.EnterAction, abortProc: NIL, abortData: NIL, abortViewer: NIL];
SVMouseEvent.InitializeFSM[svData];
svData.drag.savedCaret ← NEW[SkitterObj];
svData.camera ← SVScene.CreateCamera[worldCS, screenCS, shaded];
SVScene.StuffCameraFromFileCamera[svData.camera, fileCamera, shaded, scene];
svData.sceneStyleIndex ← 2; -- shaded
svData.mode ← cast;
svData.showCoordSys ← FALSE;
svData.refresh.startBoundBox ← SVBoundBox.NullBoundBox[];
svData.refresh.sandwich ← SVRefresh.CreateSandwich[];
svData.hitTest ← NEW[FiltersObj];
svData.hitTest.triggerBag ← SVAlign.CreateTriggerBag[svData.scene];
svData.hitTest.sceneBag ← SVAlign.CreateTriggerBag[svData.scene];
svData.hitTest.alignBag ← SVAlign.CreateAlignBag[];
svData.refresh.lineCache ← FunctionCache.Create[maxEntries: 200];
svData.gravityPool ← SVGravity.NewGravityPool[];
SVMenus.BuildControlPanel[svData, windowMenu, workingDirectory];
BuildPictureSection[svData];
viewerPicture ← svData.actionArea;
IF NOT iconic THEN ViewerOps.OpenIcon[icon: svData.outer, closeOthers: FALSE, bottom: FALSE, paint: TRUE];
};
OptimizeQueue: SlackProcess.OptimizeProc = {
PROC [qeGen: QueueEntryGenerator, actionsOnQueue: NAT] RETURNS [skipActions: NAT];
Notice that skipActions will be at most summary.count -1; The most recent action on the queue will be done if nothing else is appropriate. Always do the last During.
atom, nextAtom: ATOM;
optimizeHint: REF ANY;
hintList: LIST OF REF ANY;
IF actionsOnQueue < 2 THEN RETURN [0];
skipActions ← 0;
FOR i: NAT IN [0..actionsOnQueue-2] DO
[----, optimizeHint, ----] ← SlackProcess.GetQueueEntry[qeGen, i];
hintList ← IF optimizeHint = NIL THEN NIL ELSE NARROW[optimizeHint];
atom ← IF hintList = NIL THEN $None ELSE NARROW[hintList.first];
[----, optimizeHint, ----] ← SlackProcess.GetQueueEntry[qeGen, i+1];
hintList ← IF optimizeHint = NIL THEN NIL ELSE NARROW[optimizeHint];
nextAtom ← IF hintList = NIL THEN $None ELSE NARROW[hintList.first];
IF atom = $During AND nextAtom = $During THEN {
skipActions ← skipActions + 1;
}
ELSE RETURN;
ENDLOOP;
};
BuildPictureSection: PRIVATE PROC [svData: SVData] = {
Create a SolidWindow which fills the bottom of the container
svData.actionArea ← ViewerOps.CreateViewer[
flavor: $SolidWindow,
info: [
parent: svData.outer,
wx: 0, wy: svData.height,
ww: svData.outer.ww,
wh: svData.outer.wh, -- only initial values for ww and wh. They are constrained below
data: svData, -- contains the current scene
scrollable: FALSE
]
];
SVViewerTool.ChildXBound[svData.outer, svData.actionArea];
SVViewerTool.ChildYBound[svData.outer, svData.actionArea];
svData.height ← svData.height + svData.actionArea.wh;
}; -- end of BuildDrawSection
ReloadTipTable: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = {
newTable: TIPUser.TIPTable;
editToolData: EditToolData ← NARROW[svData.editToolData];
solidviewer: ViewerClasses.Viewer;
bad: BOOLFALSE;
tableName, msg: Rope.ROPE;
Feedback.Append[svData.feedback, "Reloading tip table...", begin];
tableName ← Rope.Concat[editToolData.originalWorkingDirectory, "Solidviews.TIP"];
newTable ← TIPUser.InstantiateNewTIPTable[tableName
! FS.Error => {
bad ← TRUE;
msg ← Rope.Concat["Cannot read TIP table file: ", tableName];
CONTINUE};
TIPUser.InvalidTable => {
bad ← TRUE;
msg ← Rope.Concat["Error(s) saved on TIP.Errors for: ", tableName];
CONTINUE}];
IF bad THEN {Feedback.Append[svData.feedback, msg, oneLiner]; RETURN};
Feedback.Append[svData.feedback, "Done.", end];
IF newTable = NIL THEN ERROR;
solidviewer ← svData.actionArea;
solidviewer.tipTable ← newTable;
};
SetCursorLooks: PUBLIC PROC [type: SVInterfaceTypes.GravityType, svData: SVData, on: BOOLTRUE] = {
The following is a hack and is NOT the right way to do business. Unfortunately, the cursor data lives in a viewer CLASS rec instead of a viewer INSTANCE rec so their is no easy way to keep an instance-specific cursor.
newCursor: Cursors.CursorType;
mouseViewer: ViewerClasses.Viewer;
client: BOOL;
terminal: Terminal.Virtual ← Terminal.Current[];
mousePos: Terminal.Position ← Terminal.GetMousePosition[terminal]; -- mouse origin in upper left
tipScreenCoords: TIPUser.TIPScreenCoords ← NEW[TIPUser.TIPScreenCoordsRec ← [mouseX: mousePos.x, mouseY: mousePos.y, color: svData.actionArea.column=color] ];
tipScreenCoords.mouseY ← IF svData.actionArea.column=color THEN terminal.colorHeight-mousePos.y ELSE terminal.bwHeight-mousePos.y; -- move mouse origin to lower left
[mouseViewer, client] ← ViewerOps.MouseInViewer[tipScreenCoords];
svData.actionArea.class.cursor ← newCursor ←
IF NOT on THEN offCursor
ELSE SELECT type FROM
pointsPreferred => pointsPreferredCursor,
linesPreferred => strictDistanceCursor,
facesPreferred => offCursor,
ENDCASE => ERROR;
change the cursor immediately if the mouse is in the action area
IF mouseViewer=svData.actionArea AND client THEN Cursors.SetCursor[newCursor];
};
NewCaretPos: PUBLIC PROC [svData: SVData] = {
caret0, caret1, caret2Pos: Point3d;
slope, azimuth: REAL;
editToolData: EditToolData ← svData.editToolData;
caret0 ← svData.measure.caret0;
caret1 ← svData.measure.caret1;
caret2Pos ← SVVector3d.Scale[SVCaret.GetPoint[editToolData.skitter], 1.0/svData.hitTest.scaleUnit];
svData.measure.caret2Value ← caret2Pos;
SVViewerTools.SetPoint[svData.measure.caret2, caret2Pos];
[azimuth, slope] ← SVMeasure.AzimuthAndSlopeOfPoints[caret1, caret2Pos];
svData.measure.azimuthViewValue ← azimuth;
SVViewerTools.SetReal[svData.measure.azimuthView, azimuth];
svData.measure.slopeViewValue ← slope;
SVViewerTools.SetReal[svData.measure.slopeView, slope];
};
SaveCaretPos: PUBLIC PROC [svData: SVData] = {
editToolData: EditToolData ← svData.editToolData;
caret2Pos: Point3d ← SVVector3d.Scale[SVCaret.GetPoint[editToolData.skitter], 1.0/svData.hitTest.scaleUnit];
svData.measure.caret2Value ← caret2Pos;
SVViewerTools.SetPoint[svData.measure.caret2, caret2Pos];
svData.measure.caret0 ← svData.measure.caret1;
svData.measure.caret1 ← caret2Pos;
};
BuildCursors: PROC [] = {
pointsPreferredArray: Cursors.CursorArray = [600B+1100B, 600B+1100B+2040B, 2040B+4020B, 4020B+10010B, 10010B+20004B, 20004B+40002B, 40002B+100001B, 40002B+100001B, 40002B+100001B, 40002B+100001B, 20004B+40002B, 10010B+20004B, 4020B+10010B, 2040B+4020B, 600B+1100B+2040B, 600B+1100B]; -- diamond
strictDistanceArray: Cursors.CursorArray = [100001B+40002B, 40002B+20004B, 20004B+10010B, 10010B+4020B, 4020B+2040B, 2040B, 0, 0, 0, 0, 2040B, 4020B+2040B, 10010B+4020B, 20004B+10010B, 40002B+20004B, 100001B+40002B]; -- folded diamond
offArray: Cursors.CursorArray = [177777B, 177777B, 140003B, 140003B, 140003B, 140003B, 140003B, 140003B, 140003B, 140003B, 140003B, 140003B, 140003B, 140003B, 177777B, 177777B]; -- square
pointsPreferredCursor ← Cursors.NewCursor[bits: pointsPreferredArray, hotX: -8, hotY: -6];
strictDistanceCursor ← Cursors.NewCursor[bits: strictDistanceArray, hotX: -8, hotY: -5];
offCursor ← Cursors.NewCursor[bits: offArray, hotX: -8, hotY: -6];
};
Init: PROC = {
solidWindowClass: ViewerClasses.ViewerClass;
solidWindowClass ←
NEW[ViewerClasses.ViewerClassRec ← [
paint: SVActionAreaPaint,
notify: SVUserInput.InputNotify,
tipTable: TIPUser.InstantiateNewTIPTable["SolidViews.TIP"]
]];
ViewerOps.RegisterViewerClass[$SolidWindow, solidWindowClass];
BuildCursors[];
originalWDir ← FileNames.CurrentWorkingDirectory[];
};
offCursor: Cursors.CursorType; -- filled in by BuildCursors
pointsPreferredCursor: Cursors.CursorType; -- filled in by BuildCursors
strictDistanceCursor: Cursors.CursorType; -- filled in by BuildCursors
originalWDir: Rope.ROPENIL; -- filled in by Init
Init[];
END.