<> <> <> <> <> <> DIRECTORY Commander, FileNames, FS, GGCaret, GGContainer, GGError, GGInterfaceTypes, GGMenus, GGModelTypes, GGObjects, GGRefresh, GGUserInput, GGVector, GGViewerOps, GGWindow, Icons, Imager, ImagerBackdoor, IO, Menus, Rope, TiogaButtons, TIPUser, ViewerClasses, ViewerOps; GGWindowImpl: CEDAR PROGRAM IMPORTS Commander, FileNames, FS, GGCaret, Icons, Imager, ImagerBackdoor, GGContainer, GGError, GGMenus, GGObjects, GGRefresh, GGUserInput, GGVector, GGViewerOps, Menus, Rope, TIPUser, ViewerOps EXPORTS GGWindow SHARES ViewerClasses = BEGIN Camera: TYPE = REF CameraObj; CameraObj: TYPE = GGModelTypes.CameraObj; Caret: TYPE = REF CaretObj; CaretObj: TYPE = GGInterfaceTypes.CaretObj; Cluster: TYPE = GGModelTypes.Cluster; ImagerProc: TYPE = GGInterfaceTypes.ImagerProc; MouseButton: TYPE = Menus.MouseButton; Outline: TYPE = GGModelTypes.Outline; PaintQueue: TYPE = REF PaintQueueObj; PaintQueueObj: TYPE = GGInterfaceTypes.PaintQueueObj; Point: TYPE = GGModelTypes.Point; Scene: TYPE = REF SceneObj; SceneObj: TYPE = GGModelTypes.SceneObj; Segment: TYPE = GGModelTypes.Segment; Sequence: TYPE = GGModelTypes.Sequence; Traj: TYPE = GGModelTypes.Traj; Viewer: TYPE = ViewerClasses.Viewer; GargoyleData: TYPE = REF GargoyleDataObj; GargoyleDataObj: TYPE = GGInterfaceTypes.GargoyleDataObj; 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; nameSize: CARDINAL = 140; smallNumberSize: CARDINAL = 45; numberSize: CARDINAL = 80; bigNumberSize: CARDINAL = 160; pointSize: CARDINAL = 160; ActionAreaPaint: PROC [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] RETURNS [quit: BOOL _ FALSE] = TRUSTED { <> <> gargoyleData: GargoyleData; IF whatChanged = NIL THEN { --we are being called by Window Manager gargoyleData _ NARROW[self.data]; PlaceOrigin[self]; Painter[$PaintEntireScene, gargoyleData]; } ELSE { gargoyleData _ NARROW[whatChanged]; GGRefresh.ActionAreaPaint[context, gargoyleData.refresh.paintAction, gargoyleData]; }; }; Painter: PUBLIC PROC [paintAction: ATOM, gargoyleData: GargoyleData] = { gargoyleData.refresh.paintAction _ paintAction; ViewerOps.PaintViewer[ viewer: gargoyleData.actionArea, hint: client, whatChanged: gargoyleData, clearClient: FALSE]; }; -- end of Painter PlaceOrigin: PROC [viewer: Viewer] = TRUSTED { <> << Find the center of the ActionArea in viewer coordinates.>> originX, originY: INTEGER; rect: Imager.Rectangle; gargoyleData: GargoyleData _ NARROW[viewer.data]; originX _ viewer.cw; -- convert window width to real originY _ viewer.ch; -- convert window height to real originX _ originX/2; -- find the midpoint in window coords originY _ originY/2; gargoyleData.camera.cameraScreen _ [originX, originY]; gargoyleData.refresh.backgroundBitmap _ ImagerBackdoor.NewBitmap[viewer.cw, viewer.ch]; gargoyleData.refresh.backgroundContext _ ImagerBackdoor.BitmapContext[gargoyleData.refresh.backgroundBitmap]; gargoyleData.refresh.chunkingBitmap _ ImagerBackdoor.NewBitmap[viewer.cw, viewer.ch]; gargoyleData.refresh.chunkingContext _ ImagerBackdoor.BitmapContext[gargoyleData.refresh.chunkingBitmap]; <> rect _ ImagerBackdoor.GetBounds[gargoyleData.refresh.backgroundContext]; Imager.SetColor[gargoyleData.refresh.backgroundContext, Imager.white]; Imager.MaskRectangle[gargoyleData.refresh.backgroundContext, rect]; }; CameraToScreen: PUBLIC PROC [pointCamera: Point, camera: Camera] RETURNS [pointScreen: Point] = { pointScreen _ GGVector.Add[pointCamera, camera.cameraScreen]; }; ScreenToCamera: PUBLIC PROC [pointScreen: Point, camera: Camera] RETURNS [pointCamera: Point] = { pointCamera _ GGVector.Sub[pointScreen, camera.cameraScreen]; }; ScreenToWorld: PUBLIC PROC [pointScreen: Point, camera: Camera] RETURNS [pointWorld: Point] = { pointCamera: Point; pointCamera _ GGVector.Sub[pointScreen, camera.cameraScreen]; pointWorld _ GGVector.Add[pointCamera, camera.cameraWorld]; }; Init: PROC = { actionAreaClass: ViewerClasses.ViewerClass; actionAreaClass _ NEW[ViewerClasses.ViewerClassRec _ [ paint: ActionAreaPaint, notify: GGUserInput.InputNotify, tipTable: TIPUser.InstantiateNewTIPTable["Gargoyle.TIP"] ]]; ViewerOps.RegisterViewerClass[$ActionArea, actionAreaClass]; Commander.Register[ key: "Gargoyle", proc: NewWindow, doc: "Create a Gargoyle Graphics Window", clientData: NIL ]; }; NewWindow: Commander.CommandProc = { scene: Scene _ GGObjects.CreateScene[]; [] _ CreateWindow[scene, TRUE, TRUE, FileNames.CurrentWorkingDirectory[]]; }; CreateWindow: PUBLIC PROC [scene: Scene, iconic: BOOL, paint: BOOL, workingDirectory: Rope.ROPE] RETURNS [gargoyleData: GargoyleData] = { <> <> windowMenu: Menus.Menu _ Menus.CreateMenu[3]; iconFileName: Rope.ROPE; gargoyleData _ NEW[GargoyleDataObj]; gargoyleData.originalWorkingDirectory _ FileNames.CurrentWorkingDirectory[]; gargoyleData.scene _ scene; gargoyleData.camera _ NEW[CameraObj _ [[0.0, 0.0], 1.0, [0.0, 0.0]]]; gargoyleData.caret _ NEW[CaretObj]; gargoyleData.anchor _ NEW[CaretObj]; gargoyleData.currentAction _ $None; <> iconFileName _ Rope.Concat[gargoyleData.originalWorkingDirectory, "Gargoyle.icons"]; gargoyleData.outer _ GGContainer.Create[ info: [ name: "Gargoyle", menu: windowMenu, data: gargoyleData, iconic: TRUE, column: left, scrollable: FALSE, icon: Icons.NewIconFromFile[iconFileName, 0] ], paint: FALSE]; GGMenus.BuildControlPanel[gargoyleData, windowMenu]; BuildActionArea[gargoyleData]; ViewerOps.OpenIcon[icon: gargoyleData.outer, closeOthers: FALSE, bottom: FALSE, paint: TRUE]; }; BuildActionArea: PRIVATE PROC [gargoyleData: GargoyleData] = { <> gargoyleData.actionArea _ ViewerOps.CreateViewer[ flavor: $ActionArea, info: [ parent: gargoyleData.outer, wx: 0, wy: gargoyleData.height, ww: gargoyleData.outer.ww, wh: gargoyleData.outer.wh, -- only initial values for ww and wh. They are constrained below data: gargoyleData, scrollable: FALSE ] ]; GGContainer.ChildXBound[gargoyleData.outer, gargoyleData.actionArea]; GGContainer.ChildYBound[gargoyleData.outer, gargoyleData.actionArea]; gargoyleData.height _ gargoyleData.height + gargoyleData.actionArea.wh; }; -- end of BuildActionArea ReloadTipTable: PUBLIC PROC [gargoyleData: GargoyleData] = { newTable: TIPUser.TIPTable; actionArea: ViewerClasses.Viewer; bad: BOOL _ FALSE; tableName, msg: Rope.ROPE; GGError.AppendHerald["Reloading tip table...", TRUE]; tableName _ Rope.Concat[gargoyleData.originalWorkingDirectory, "Gargoyle.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 {GGError.Append[msg, oneLiner]; RETURN}; GGError.AppendHerald["Done.", FALSE]; IF newTable = NIL THEN ERROR; actionArea _ gargoyleData.actionArea; actionArea.tipTable _ newTable; }; NewCaretPos: PUBLIC PROC [gargoyleData: GargoyleData] = { oldCaretPos, newCaretPos: Point; success: BOOL; distance: REAL; [oldCaretPos, success] _ GGViewerOps.GetPoint[gargoyleData.distanceLine.oldCaret]; newCaretPos _ GGCaret.GetPoint[gargoyleData.caret]; IF NOT success THEN RETURN; distance _ GGVector.Distance[oldCaretPos, newCaretPos]; GGViewerOps.SetReal[gargoyleData.distanceLine.distance, distance]; GGViewerOps.SetPoint[gargoyleData.distanceLine.newCaret, newCaretPos]; }; SaveCaretPos: PUBLIC PROC [gargoyleData: GargoyleData] = { caretPos: Point; caretPos _ GGCaret.GetPoint[gargoyleData.caret]; GGViewerOps.SetPoint[gargoyleData.distanceLine.oldCaret, caretPos]; }; Init[]; END.