<> <> <> <> <> <> <<>> <> DIRECTORY AtomButtons, AtomButtonsTypes, BiScrollers, CodeTimer, Commander, CommandTool, Cursors, Feedback, FeedbackOps, FileNames, FS, Geom2D, GGAlign, GGBasicTypes, GGBoundBox, GGCaret, GGContainer, GGControlPanelTypes, GGCoreOps, GGDragTypes, GGEmbedTypes, GGEvent, GGHistory, GGHistoryTypes, GGInterfaceTypes, GGMeasure, GGMenu, GGModelTypes, GGMouseEvent, GGMultiGravity, GGOutline, GGRefresh, GGRefreshTypes, GGScene, GGSegmentTypes, GGSessionLog, GGSlice, GGState, GGStateExtras, GGStateTypes, GGUserInput, GGUserProfile, GGViewerOps, GGWindow, Icons, Imager, ImagerFont, ImagerTransformation, IO, MultiCursors, Process, Rope, SlackProcess, TiogaButtons, TIPPrivate, TIPUser, TIPUserExtras, UserProfile, Vectors2d, ViewerClasses, ViewerOps; GGWindowImpl: CEDAR PROGRAM IMPORTS AtomButtons, BiScrollers, CodeTimer, Commander, CommandTool, Cursors, Feedback, FeedbackOps, FileNames, FS, Geom2D, GGAlign, GGBoundBox, GGCaret, GGContainer, GGCoreOps, GGEvent, GGHistory, GGMeasure, GGMenu, GGMouseEvent, GGMultiGravity, GGOutline, GGRefresh, GGScene, GGSessionLog, GGSlice, GGState, GGStateExtras, GGUserInput, GGUserProfile, GGViewerOps, Icons, Imager, ImagerFont, ImagerTransformation, IO, MultiCursors, Process, Rope, SlackProcess, TIPPrivate, TIPUser, TIPUserExtras, UserProfile, Vectors2d, ViewerOps EXPORTS GGWindow, GGHistoryTypes, GGInterfaceTypes = BEGIN ControlsObj: PUBLIC TYPE = GGControlPanelTypes.ControlsObj; -- exported to GGInterfaceTypes EmbedDataObj: PUBLIC TYPE = GGEmbedTypes.EmbedDataObj; -- exported to GGInterfaceTypes StateDataObj: PUBLIC TYPE = GGStateTypes.StateDataObj; -- exported to GGInterfaceTypes DragDataObj: PUBLIC TYPE = GGDragTypes.DragDataObj; -- exported to GGInterfaceTypes CameraObj: TYPE = GGModelTypes.CameraObj; Caret: TYPE = REF CaretObj; CaretObj: TYPE = GGInterfaceTypes.CaretObj; DebugDataObj: TYPE = GGInterfaceTypes.DebugDataObj; Filters: TYPE = REF FiltersObj; FiltersObj: TYPE = GGInterfaceTypes.FiltersObj; ForegroundParts: TYPE = GGWindow.ForegroundParts; GGDataObj: TYPE = GGInterfaceTypes.GGDataObj; GGData: TYPE = GGInterfaceTypes.GGData; HistoryTool: TYPE = REF HistoryToolObj; HistoryToolObj: PUBLIC TYPE = GGHistory.HistoryToolObj; -- exported to GGHistoryTypes ImagerProc: TYPE = GGInterfaceTypes.ImagerProc; Point: TYPE = GGBasicTypes.Point; RefreshDataObj: PUBLIC TYPE = GGRefreshTypes.RefreshDataObj; ROPE: TYPE = Rope.ROPE; Scene: TYPE = REF SceneObj; SceneObj: TYPE = GGModelTypes.SceneObj; Segment: TYPE = GGSegmentTypes.Segment; Sequence: TYPE = GGModelTypes.Sequence; Slice: TYPE = GGModelTypes.Slice; Traj: TYPE = GGModelTypes.Traj; Transformation: TYPE = ImagerTransformation.Transformation; Viewer: TYPE = ViewerClasses.Viewer; buttonAlign: INTEGER _ 2; -- align popUp and standard buttons in first button line 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; globalEditedProcList: LIST OF EditedProcItem; <> RestoreScreenAndInvariants: PUBLIC PROC [paintAction: ATOM, ggData: GGData, remake: ForegroundParts _ triggerBag, edited: BOOL _ TRUE, okToSkipCapture: BOOL] = { <> <> CodeTimer.StartInt[$RestoreScreenAndInvariants, $Gargoyle]; IF ggData.aborted[bags] THEN { GGAlign.SetStaticBags[ggData]; GGRefresh.InvalidateForeground[ggData]; GGRefresh.InvalidateBackground[ggData]; ggData.aborted[bags] _ FALSE; } ELSE { SELECT remake FROM none => NULL; triggerBag => { GGAlign.SetStaticBags[ggData]; GGRefresh.InvalidateForeground[ggData]; }; triggerBagNotSceneBag => { GGAlign.SetStaticTriggerAndAlignBags[ggData]; GGRefresh.InvalidateForeground[ggData]; }; alignBag => { GGAlign.FlushAlignBag[ggData.hitTest.alignBag]; GGAlign.FillStaticAlignBag[ggData.hitTest.triggerBag, ggData.hitTest.sceneBag, ggData, NOT GGState.GetShowAlignments[ggData], ggData.hitTest.alignBag]; GGRefresh.InvalidateForeground[ggData]; }; bitMap => { GGRefresh.InvalidateForeground[ggData]; }; sceneBag => { GGAlign.FlushTriggerBag[ggData.hitTest.sceneBag]; GGAlign.FillStaticSceneBag[ggData.scene, ggData.hitTest.sceneBag]; }; ENDCASE => ERROR; }; <> IF edited THEN { FOR list: LIST OF EditedProcItem _ globalEditedProcList, list.rest UNTIL list = NIL DO IF ggData=list.first.ggData THEN list.first.editedProc[ggData, list.first.clientData]; ENDLOOP; }; <> GGRefresh.PaintInParent[ggData, paintAction]; IF NOT okToSkipCapture THEN GGHistory.DoAdvanceCapture[ggData: ggData]; CodeTimer.StopInt[$RestoreScreenAndInvariants, $Gargoyle]; }; NewCaretPos: PUBLIC PROC [ggData: GGData] = { caret0, caret1, caret2Pos: Point; distance, angle, slope, lineDist: REAL; caret0 _ ggData.measure.caret0; caret1 _ ggData.measure.caret1; caret2Pos _ Vectors2d.Scale[GGCaret.GetPoint[ggData.caret], 1.0/ggData.hitTest.scaleUnit]; distance _ GGMeasure.DistanceBetweenPoints[caret1, caret2Pos]; -- distance in scaleUnits angle _ GGMeasure.SmallestAngleOfPoints[caret0, caret1, caret2Pos]; slope _ GGMeasure.SlopeOfPoints[caret1, caret2Pos]; lineDist _ GGMeasure.DistanceFromPointToLine[caret2Pos, caret0, caret1]; -- line distance in scaleUnits ggData.measure.caret2Value _ caret2Pos; GGViewerOps.SetPoint[ggData.controls.caret2, caret2Pos]; GGState.SetSlopeValue[ggData, slope]; GGState.SetAngleValue[ggData, angle]; GGState.SetRadiusValue[ggData, distance]; GGState.SetLineDistanceValue[ggData, lineDist]; }; SaveCaretPos: PUBLIC PROC [ggData: GGData] = { caret2Pos: Point _ Vectors2d.Scale[GGCaret.GetPoint[ggData.caret], 1.0/ggData.hitTest.scaleUnit]; ggData.measure.caret2Value _ caret2Pos; GGViewerOps.SetPoint[ggData.controls.caret2, caret2Pos]; ggData.measure.caret0 _ ggData.measure.caret1; ggData.measure.caret1 _ caret2Pos; }; <<>> <> OpenViewerOnFile: PROC [fileName: Rope.ROPE _ NIL, fancyPanel: BOOL _ FALSE] = { ggData: GGData _ CreateWindowAux[GGScene.CreateScene[], TRUE, FALSE, FileNames.CurrentWorkingDirectory[], fancyPanel]; -- create brand new GG window IF fileName#NIL AND ~Rope.Equal[fileName, ""] THEN GGEvent.Get[event: LIST[$Get, fileName], ggData: ggData]; -- tell GGEvent.Get to try for this file GGHistory.CapTool[ggData.controls.topper.name, ggData]; ViewerOps.PaintViewer[ggData.controls.topper, caption]; -- just to get the icon to appear ViewerOps.PaintViewer[ggData.controls.panel, caption]; -- just to get the icon to appear }; CreateChildViewer: PUBLIC PROC [ scene: Scene, wx, wy: INTEGER _ 0, ww, wh: INTEGER _ 0, cx, cy: INTEGER _ 0, cw, ch: INTEGER _ 0, parent: Viewer, workingDirectory: Rope.ROPE, clientData: REF ANY _ NIL, paint: BOOL _ TRUE] RETURNS [viewer: Viewer, ggData: GGData] = { ggData _ CreateGGDataForViewer[parent, scene, workingDirectory]; ggData.controls.active _ TRUE; ggData.controls.biScroller _ BiScrollers.GetStyle[].CreateBiScroller[ class: actionAreaClass, info: [ parent: parent, name: "GargoyleChild", wx: wx, wy: wy, ww: ww, wh: wh, cx: cx, cy: cy, cw: cw, ch: ch, data: ggData, border: FALSE, scrollable: FALSE], paint: paint ]; ggData.controls.picture _ ggData.controls.topper _ ggData.controls.biScroller.QuaViewer[inner: FALSE]; ggData.controls.actionArea _ ggData.controls.biScroller.QuaViewer[inner: TRUE]; ggData.controls.actionArea.cursor _ last; -- "last" means that Viewers should not do cursor handling for us ggData.height _ 0; ggData.parseInfo _ TIPPrivate.CreateParseInfo[ggTipTable]; ggData.controls.topper.newVersion _ FALSE; ggData.controls.panel.newVersion _ FALSE; ggData.controls.picture.newVersion _ FALSE; SetCursorLooks[ggData.hitTest.gravityType, ggData]; <<[] _ SlackProcess.EnableAborts[handle: ggData.slackHandle];>> GGEvent.OpenAutoScript[ggData, TRUE]; RegisterEditedProc[ggData, GGState.GGEdited, NIL]; RestoreScreenAndInvariants[$None, ggData, triggerBag, FALSE, FALSE]; viewer _ ggData.controls.picture; <> ggData.router _ Feedback.CreateRouter[]; FeedbackOps.SetMultiMessageWindow[ggData.router, TRUE, LIST[$Error, $Complaint]]; -- blink FeedbackOps.SetMultiMessageWindow[ggData.router, FALSE, LIST[$DuringMouse, $Feedback, $Warning, $Confirm, $Show, $Statistics]]; FeedbackOps.SetMultiTypescript[ggData.router, $Gargoyle, LIST[$Error, $Warning, $Show, $Typescript, $Complaint, $Statistics]]; ggData.embed.beingBorn _ FALSE; }; PaintInViewer: PUBLIC GGRefresh.PaintProc = { <> <> ViewerOps.PaintViewer[viewer: ggData.controls.actionArea, hint: client, whatChanged: ggData, clearClient: FALSE]; }; CreateGGData: PUBLIC PROC [scene: Scene, workingDirectory: Rope.ROPE] RETURNS [ggData: GGData] = { RETURN[CreateGGDataForViewer[NIL, scene, workingDirectory]]; }; CreateGGDataForViewer: PROC [outer: Viewer, scene: Scene, workingDirectory: Rope.ROPE] RETURNS [ggData: GGData] = { ggData _ NEW[GGDataObj]; ggData.controls _ NEW[ControlsObj]; ggData.controlState _ NEW[StateDataObj]; ggData.controlState.doubleBuffer _ TRUE; ggData.controlState.clientToViewer _ ImagerTransformation.Scale[1.0]; ggData.controlState.viewerToClient _ ImagerTransformation.Scale[1.0]; ggData.drag _ NEW[DragDataObj]; ggData.embed _ NEW[EmbedDataObj]; ggData.embed.scrollDue _ ImagerTransformation.Scale[1.0]; GGRefresh.RegisterPaintProc[ggData, PaintInViewer, NIL]; GGStateExtras.RegisterViewportProc[ggData, GGStateExtras.DefaultViewport, NIL]; ggData.embed.beingBorn _ TRUE; <> IF outer#NIL THEN { outer.newVersion _ FALSE; ggData.controls.topper _ ggData.controls.panel _ outer; }; <> GGStateExtras.SetWorkingDirectory[ggData, workingDirectory]; <> ggData.scene _ scene; ggData.caret _ GGCaret.Create[]; ggData.drag.savedCaret _ GGCaret.Create[]; ggData.anchor _ GGCaret.Create[]; ggData.camera _ NEW[CameraObj]; <> ggData.lastEvents _ GGCoreOps.NewEventListt[]; GGMouseEvent.InitializeFSM[ggData]; ggData.history _ [list: LIST[NIL], maxSize: GGUserProfile.GetDefaultHistorySize[], currentIndex: 0]; -- KAP July 7, 1988 <> ggData.slackHandle _ SlackProcess.Create[queueSize: 50, logSize: 50, optimizeProc: OptimizeQueue, loggingProc: GGSessionLog.EnterAction, abortProc: GGAbortProc, abortData: ggData, abortViewer: ggData.controls.actionArea]; [] _ SlackProcess.EnableAborts[handle: ggData.slackHandle]; <> ggData.drag.selectState _ none; ggData.drag.extendMode _ none; GGState.SetSelectionCycler[ggData, GGMultiGravity.EmptyCycler[[0.0, 0.0]] ]; <> ggData.hitTest _ NEW[FiltersObj]; ggData.hitTest.triggerBag _ GGAlign.CreateTriggerBag[]; ggData.hitTest.oldTriggerBag _ GGAlign.CreateTriggerBag[]; ggData.hitTest.sceneBag _ GGAlign.CreateTriggerBag[]; ggData.hitTest.oldSceneBag _ GGAlign.CreateTriggerBag[]; ggData.hitTest.alignBag _ GGAlign.CreateAlignBag[]; ggData.hitTest.oldAlignBag _ GGAlign.CreateAlignBag[]; ggData.multiGravityPool _ GGMultiGravity.NewMultiGravityPool[]; <> ggData.refresh _ NEW[RefreshDataObj]; GGAlign.CreateLineTable[ggData]; ggData.refresh.startBoundBox _ GGBoundBox.NullBoundBox[]; ggData.refresh.beforeBox _ GGBoundBox.NullBoundBox[]; ggData.refresh.paintBox _ GGBoundBox.NullBoundBox[]; ggData.refresh.totalBox _ GGBoundBox.NullBoundBox[]; ggData.refresh.sandwich _ GGRefresh.CreateSandwich[]; ggData.refresh.oldTransform _ ImagerTransformation.Scale[1.0]; <> ggData.behavior.activeDoc _ NIL; -- next time this field is needed it will be recomputed ggData.rootSlice _ GGSlice.MakeCircleSlice[[200.0, 200.0], [300.0, 200.0]].slice; <> <> ggData.debug _ NEW[DebugDataObj]; ggData.debug.autoScriptNames _ GGCoreOps.NewRopeListt[]; <> ggData.defaults _ NEW[GGModelTypes.DefaultDataObj _ [ strokeColor: Imager.black, fillColor: GGOutline.fillColor, textColor: Imager.black, font: GGUserProfile.GetDefaultDefaultFont[], dropShadowColor: Imager.black ]]; }; CreateWindow: PUBLIC PROC [scene: Scene, iconic: BOOL, paint: BOOL, workingDirectory: Rope.ROPE] RETURNS [ggData: GGData] = { fancyPanel: BOOL _ UserProfile.Boolean[key: "Gargoyle.FancyPanel", default: TRUE]; RETURN[CreateWindowAux[scene, iconic, paint, workingDirectory, fancyPanel]]; }; CreateWindowAux: PUBLIC PROC [scene: Scene, iconic: BOOL, paint: BOOL, workingDirectory: Rope.ROPE, fancyPanel: BOOL _ FALSE] RETURNS [ggData: GGData] = { <> <> <> <<>> <> <> ggData _ CreateGGData[scene, workingDirectory]; ggData.controls.panel _ GGContainer.GGContainerCreate[ info: [ name: "GGPanel: Gargoyle", menu: NIL, data: ggData, iconic: iconic, column: left, scrollable: FALSE, icon: panelIconG ], paint: paint]; ggData.controls.biScroller _ BiScrollers.GetStyle[].CreateBiScroller[ class: actionAreaClass, info: [ parent: IF GGUserProfile.GetSeparateControlPanel[] THEN NIL ELSE ggData.controls.panel, name: "Gargoyle", menu: NIL, wx: 0, wy: 0, ww: 10, wh: 10, -- only dummy values for ww and wh for now data: ggData, iconic: TRUE, column: left, icon: noNameIconG, border: FALSE, scrollable: FALSE], paint: FALSE ]; ggData.controls.picture _ ggData.controls.topper _ ggData.controls.biScroller.QuaViewer[inner: FALSE]; ggData.controls.actionArea _ ggData.controls.biScroller.QuaViewer[inner: TRUE]; ggData.controls.actionArea.cursor _ last; -- "last" means that Viewers should not do cursor handling for us ggData.height _ 0; ggData.parseInfo _ TIPPrivate.CreateParseInfo[ggTipTable]; GGMenu.BuildControlPanel[ggData, fancyPanel]; -- updates ggData.height IF NOT GGUserProfile.GetSeparateControlPanel[] THEN { -- panel and picture together GGContainer.ChildXBound[gargoyleContainer: ggData.controls.panel, child: ggData.controls.picture]; GGContainer.ChildYBound[gargoyleContainer: ggData.controls.panel, child: ggData.controls.picture]; ViewerOps.MoveViewer[ggData.controls.picture, 0, ggData.height, ggData.controls.panel.cw, ggData.controls.panel.ch-ggData.height, FALSE]; ggData.controls.topper _ ggData.controls.panel; ggData.controls.topper.icon _ noNameIconG; ggData.controls.topper.name _ "Gargoyle"; } ELSE { -- panel by itself thisViewer: AtomButtons.ButtonLineEntry _ [label[name: "Control", font: bigFont]]; noPicture: AtomButtons.ButtonLineEntry _ [label[name: "Panel", font: bigFont]]; ViewerOps.SetOpenHeight[ggData.controls.panel, ggData.height-entryVSpace]; [] _ AtomButtons.BuildButtonLine[container: ggData.controls.panel, x: 36, y: ggData.height, clientData: ggData, handleProc: GGUserInput.EventNotify, entries: LIST[thisViewer], horizontalSpace: entryHSpace, lineHeight: 144]; ggData.height _ ggData.height + 144; [] _ AtomButtons.BuildButtonLine[container: ggData.controls.panel, x: 36, y: ggData.height, clientData: ggData, handleProc: GGUserInput.EventNotify, entries: LIST[noPicture], horizontalSpace: entryHSpace, lineHeight: 72]; ggData.height _ ggData.height + 72; }; ggData.controls.topper.newVersion _ FALSE; ggData.controls.panel.newVersion _ FALSE; ggData.controls.picture.newVersion _ FALSE; SetCursorLooks[ggData.hitTest.gravityType, ggData]; <<[] _ SlackProcess.EnableAborts[handle: ggData.slackHandle];>> GGEvent.OpenAutoScript[ggData, TRUE]; RegisterEditedProc[ggData, GGState.GGEdited, NIL]; IF GGUserProfile.GetAutoOpenHistory[] THEN ggData.history.tool _ GGHistory.BuildTool["Gargoyle", ggData]; IF GGUserProfile.GetAutoOpenTypescript[] THEN [] _ FeedbackOps.CreateNamedTypescript["Gargoyle Typescript", $Gargoyle, 120]; ggData.embed.beingBorn _ FALSE; -- enable input handling }; ActiveInGGData: AtomButtons.InitTwoStateProc = { ggData: GGData _ NARROW[clientData]; ggData.controls.activeButton _ twoState; }; GGActionAreaPaint: PROC [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] RETURNS [quit: BOOL _ FALSE] = { <> ggData: GGData ~ NARROW[BiScrollers.ClientDataOfViewer[self]]; sanityCheck: BOOL[TRUE..TRUE] ~ (ggData.controls.actionArea=self); clientToViewer: Imager.Transformation ~ GGState.GetBiScrollersTransform[ggData]; IF whatChanged=NIL THEN { -- window scrolled or changed size or changed displays action: ATOM _ $ViewersPaintEntireScene; GGRefresh.SetScreen[ggData, self.cw, self.ch, context]; -- resize sandwich, if needed <> IF ggData.refresh.clientToViewer#NIL AND ImagerTransformation.Equal[clientToViewer, ggData.refresh.clientToViewer] THEN action _ $ViewersPaintAllPlanes; GGUserInput.EventNotify[ggData, LIST[action]]; -- queue the paint action } ELSE { paintAction: ATOM _ ggData.refresh.paintAction; GGRefresh.ActionAreaPaint[screen: context, whatHasChanged: paintAction, ggData: ggData, handleViewerAbort: (whatChanged=NIL)]; ggData.refresh.clientToViewer _ clientToViewer; -- for next time around }; }; GGAbortProc: PROC [data: REF ANY] = { -- called by SlackProcess when user signals for abort ggData: GGData _ NARROW[data]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Queued operations Aborted"]; ggData.refresh.suppressRefresh _ FALSE; -- in case you killed FastPlayback ggData.refresh.suppressScreen _ FALSE; -- in case you killed FastPlayback ggData.aborted _ ALL[TRUE]; -- copies of aborted for all purposes }; <<>> RegisterEditedProc: PUBLIC PROC [ggData: GGData, editedProc: EditedProc, clientData: REF ANY] = { <> editedProcItem: EditedProcItem _ NEW[EditedProcItemObj _ [ggData, editedProc, clientData]]; globalEditedProcList _ CONS[editedProcItem, globalEditedProcList]; }; ViewerToWorld: PUBLIC PROC [viewerPoint: Point, ggData: GGData] RETURNS [worldPoint: Point] = { vec: Imager.VEC; viewerToClient: Imager.Transformation _ GGState.GetBiScrollersTransforms[ggData].viewerToClient; vec _ ImagerTransformation.Transform[viewerToClient, [x: viewerPoint.x, y: viewerPoint.y]]; worldPoint _ [vec.x, vec.y]; }; WorldToViewer: PUBLIC PROC [worldPoint: Point, ggData: GGData] RETURNS [viewerPoint: Point] = { vec: Imager.VEC; clientToViewer: Imager.Transformation _ GGState.GetBiScrollersTransform[ggData]; vec _ ImagerTransformation.Transform[clientToViewer, [x: worldPoint.x, y: worldPoint.y]]; viewerPoint _ [vec.x, vec.y]; }; <> OptimizeQueue: SlackProcess.OptimizeProc = { <> <> atom, nextAtom: ATOM; action: LIST OF REF ANY; IF actionsOnQueue < 2 THEN RETURN [0]; skipActions _ 0; FOR i: NAT IN [0..actionsOnQueue-2] DO action_ NARROW[SlackProcess.GetQueueEntry[qeGen, i].inputAction]; atom _ NARROW[action.first]; action _ NARROW[SlackProcess.GetQueueEntry[qeGen, i+1].inputAction]; nextAtom _ NARROW[action.first]; IF (atom = $During OR atom = $OneScale) AND (nextAtom = $During OR nextAtom = $OneScale) THEN skipActions _ skipActions + 1 ELSE IF (atom = $OneScroll OR atom = $OneZoom) AND (nextAtom = $OneScroll OR nextAtom = $OneZoom) THEN skipActions _ skipActions + 1 ELSE RETURN; ENDLOOP; }; PUChoiceList: PROC [r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19: AtomButtons.PopUpChoice _ [] ] RETURNS [list: AtomButtons.PopUpChoices] = { OPEN AtomButtons; InnerCons: PROC[r: PopUpChoice] = {rList _ CONS[r, rList]; }; rList: PopUpChoices; IF r0.action#NIL THEN InnerCons[r0]; IF r1.action#NIL THEN InnerCons[r1]; IF r2.action#NIL THEN InnerCons[r2]; IF r3.action#NIL THEN InnerCons[r3]; IF r4.action#NIL THEN InnerCons[r4]; IF r5.action#NIL THEN InnerCons[r5]; IF r6.action#NIL THEN InnerCons[r6]; IF r7.action#NIL THEN InnerCons[r7]; IF r8.action#NIL THEN InnerCons[r8]; IF r9.action#NIL THEN InnerCons[r9]; IF r10.action#NIL THEN InnerCons[r10]; IF r11.action#NIL THEN InnerCons[r11]; IF r12.action#NIL THEN InnerCons[r12]; IF r13.action#NIL THEN InnerCons[r13]; IF r14.action#NIL THEN InnerCons[r14]; IF r15.action#NIL THEN InnerCons[r15]; IF r16.action#NIL THEN InnerCons[r16]; IF r17.action#NIL THEN InnerCons[r17]; IF r18.action#NIL THEN InnerCons[r18]; IF r19.action#NIL THEN InnerCons[r19]; FOR dummy: PopUpChoices _ rList, dummy.rest UNTIL dummy=NIL DO list _ CONS[dummy.first, list]; ENDLOOP; }; Choice: PROC [action: LIST OF REF ANY, actionImage: Rope.ROPE, doc: Rope.ROPE, font: Imager.Font _ NIL] RETURNS [AtomButtons.PopUpChoice]= { RETURN[[action, actionImage, doc, font]]; }; List: PROC [ref1, ref2, ref3: REF ANY _ NIL] RETURNS [LIST OF REF ANY]= { RETURN[ SELECT TRUE FROM ref2=NIL => LIST[ref1], ref3=NIL => LIST[ref1, ref2], ENDCASE => LIST[ref1, ref2, ref3] ]; }; GGExtremaProc: PROC [clientData: REF ANY, direction: Geom2D.Vec] RETURNS [min, max: Geom2D.Vec] --BiScrollers.ExtremaProc-- = { <> area: Geom2D.Rect; ggData: GGData _ NARROW[clientData]; bigBox: GGBoundBox.BoundBox _ GGBoundBox.BoundBoxOfBoxes[GGScene.BoundBoxesInScene[ggData.scene].list]; area _ IF bigBox#NIL THEN [x: bigBox.loX, y: bigBox.loY, w: bigBox.hiX-bigBox.loX, h: bigBox.hiY-bigBox.loY] ELSE [0.0, 0.0, 1.0, 1.0]; [min, max] _ Geom2D.ExtremaOfRect[r: area, n: direction]; }; <> EditedProc: TYPE = GGWindow.EditedProc; EditedProcItem: TYPE = REF EditedProcItemObj; EditedProcItemObj: TYPE = RECORD [ ggData: GGData, editedProc: EditedProc, clientData: REF ANY ]; <> SetCursorLooks: PUBLIC PROC [type: GGInterfaceTypes.GravityType, ggData: GGData, off: BOOL _ FALSE ] = { newCursor: Cursors.CursorType ~ IF off THEN offCursor ELSE SELECT type FROM pointsPreferred => pointsPreferredCursor, linesPreferred, facesPreferred => linesPreferredCursor, ENDCASE => ERROR; ggData.controls.cursor _ newCursor; IF newCursor#MultiCursors.GetACursor[NIL] THEN MultiCursors.SetACursor[newCursor, NIL]; -- this code should make sure the cursor is in the Gargoyle action area before doing this. <> }; <> NewGGViewers: Commander.CommandProc = { <<[cmd: Handle] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL];>> nameList, args: LIST OF Rope.ROPE _ NIL; argLength: NAT _ 0; switchChar: CHAR = '-; fancyPanel: BOOL _ UserProfile.Boolean[key: "Gargoyle.FancyPanel", default: TRUE]; [list: args, length: argLength] _ CommandTool.ParseToList[cmd: cmd, starExpand: TRUE, switchChar: switchChar ! CommandTool.Failed => CONTINUE; ]; IF args = NIL OR argLength < 1 THEN { OpenViewerOnFile[fileName: NIL, fancyPanel: fancyPanel]; RETURN}; IF argLength = 1 AND Rope.Equal[args.first, "-fancyPanel", FALSE] THEN {OpenViewerOnFile[fileName: NIL, fancyPanel: TRUE]; RETURN}; IF argLength = 1 AND Rope.Equal[args.first, "-~fancyPanel", FALSE] THEN {OpenViewerOnFile[fileName: NIL, fancyPanel: FALSE]; RETURN}; FOR rl: LIST OF Rope.ROPE _ args, rl.rest UNTIL rl = NIL DO --open a GGViewer on each file IF Rope.Equal[rl.first, "-fancyPanel", FALSE] THEN fancyPanel _ TRUE ELSE IF Rope.Equal[rl.first, "-~fancyPanel", FALSE] THEN fancyPanel _ FALSE ELSE [] _ OpenViewerOnFile[fileName: FileNames.ResolveRelativePath[rl.first], fancyPanel: fancyPanel]; ENDLOOP; }; FilenameMinusExtension: PUBLIC PROC [wholeName: ROPE] RETURNS [ROPE] ~ { fullFName: ROPE; cp: FS.ComponentPositions; [fullFName: fullFName, cp: cp] _ FS.ExpandName[wholeName]; RETURN[Rope.Substr[fullFName, 0, cp.base.start+cp.base.length]]; }; GGToIP: Commander.CommandProc = { EachFile: FS.NameProc = { <<[fullFName: ROPE] RETURNS [continue: BOOL]>> ipName: Rope.ROPE; Process.CheckForAbort[]; ipName _ FilenameMinusExtension[fullFName]; ipName _ Rope.Concat[ipName, ".ip"]; GGEvent.Get[ggData, LIST[$Get, fullFName]]; GGEvent.ToIP[ggData, LIST[$ToIP, ipName]]; continue _ TRUE; }; TryPattern: PROC [pattern: Rope.ROPE] = { ENABLE FS.Error => IF error.group # $bug THEN { IO.PutRope[out, " -- "]; IO.PutRope[out, error.explanation]; GO TO err}; pattern _ FileNames.ResolveRelativePath[pattern]; pattern _ FS.ExpandName[pattern].fullFName; IF NOT Rope.Match["*!*", pattern] THEN pattern _ Rope.Concat[pattern, "!h"]; FS.EnumerateForNames[pattern, EachFile]; EXITS err => {IO.PutRope[out, "\n"]; RETURN}; }; out: IO.STREAM _ cmd.out; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO failed}]; ggData: GGData _ CreateWindow[GGScene.CreateScene[], TRUE, FALSE, FileNames.CurrentWorkingDirectory[]]; ViewerOps.PaintViewer[ggData.controls.panel, caption]; -- just to get the icon to appear ViewerOps.PaintViewer[ggData.controls.topper, caption]; -- just to get the icon to appear GGUserInput.EventNotify[ggData, LIST[$Typescript]]; FOR i: NAT IN [1..argv.argc) DO arg: Rope.ROPE = argv[i]; IF Rope.Length[arg] = 0 THEN LOOP; TryPattern[arg]; ENDLOOP; EXITS failed => {result _ $Failure}; }; GGIPToIP: Commander.CommandProc = { <> EachFile: FS.NameProc = { <<[fullFName: ROPE] RETURNS [continue: BOOL]>> newIPName: ROPE; Process.CheckForAbort[]; GGUserInput.EventNotify[ggData, LIST[$Clear]]; GGUserInput.EventNotify[ggData, LIST[$MergeIPEditable, fullFName]]; GGSessionLog.PlaybackFromFile[scriptName, ggData]; newIPName _ FilenameMinusExtension[fullFName]; newIPName _ Rope.Concat[newIPName, "-mod.ip"]; GGUserInput.EventNotify[ggData, LIST[$ToIP, newIPName]]; continue _ TRUE; }; TryPattern: PROC [pattern: Rope.ROPE] = { ENABLE FS.Error => IF error.group # $bug THEN { IO.PutRope[out, " -- "]; IO.PutRope[out, error.explanation]; GO TO err}; pattern _ FileNames.ResolveRelativePath[pattern]; pattern _ FS.ExpandName[pattern].fullFName; IF NOT Rope.Match["*!*", pattern] THEN pattern _ Rope.Concat[pattern, "!h"]; FS.EnumerateForNames[pattern, EachFile]; EXITS err => {IO.PutRope[out, "\n"]; RETURN}; }; out: IO.STREAM _ cmd.out; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO failed}]; scriptName: Rope.ROPE _ argv[1]; ggData: GGData _ CreateWindow[GGScene.CreateScene[], TRUE, FALSE, FileNames.CurrentWorkingDirectory[]]; ViewerOps.PaintViewer[ggData.controls.panel, caption]; -- just to get the icon to appear ViewerOps.PaintViewer[ggData.controls.topper, caption]; -- just to get the icon to appear GGUserInput.EventNotify[ggData, LIST[$Typescript]]; <> GGUserInput.EventNotify[ggData, LIST[$DisableRefresh]]; -- more kosher FOR i: NAT IN [2..argv.argc) DO arg: Rope.ROPE = argv[i]; IF Rope.Length[arg] = 0 THEN LOOP; TryPattern[arg]; ENDLOOP; GGUserInput.EventNotify[ggData, LIST[$EnableRefresh]]; GGUserInput.EventNotify[ggData, LIST[$Refresh]]; EXITS failed => {result _ $Failure}; }; GGBasicTransformProc: PROC [bs: BiScrollers.BiScroller] RETURNS [Transformation] = { <> height: REAL _ 11.0*72.0; width: REAL _ 8.5*72.0; actionArea: Viewer _ BiScrollers.QuaViewer[bs].child; ww: REAL _ actionArea.ww; wh: REAL _ actionArea.wh; transform: Transformation; transform _ ImagerTransformation.Translate[[(ww-width)/2.0, (wh-height)/2.0]]; RETURN[transform]; }; BSSaveProc: PRIVATE ViewerClasses.SaveProc = { <<[self: ViewerClasses.Viewer, force: BOOL _ FALSE]>> <> GGContainer.GargoyleContainerSave[self, force]; }; BSDestroyProc: PRIVATE ViewerClasses.DestroyProc = { <> <> IF ggData#NIL AND ggData.controls.topper=ggData.controls.picture AND ggData.controls.panel.destroyed THEN GGUserInput.EventNotify[ggData, LIST[$Destroy]]; -- frees much garbage>> <> }; Init: PROC = { ggTipTable _ TIPUser.InstantiateNewTIPTable["Gargoyle.tip"]; -- used in ggData.parseInfo actionAreaClass _ BiScrollers.GetStyle[].NewBiScrollerClass[[ flavor: $ActionArea, save: BSSaveProc, destroy: BSDestroyProc, extrema: GGExtremaProc, notify: GGUserInput.InputNotify, bsUserAction: GGUserInput.BiScrollerInputNotify, paint: GGActionAreaPaint, tipTable: TIPUserExtras.TransparentTIPTable[], -- the real tipTable is in ggData.parseInfo mayStretch: FALSE, -- NOT OK to scale X and Y differently offsetsMustBeIntegers: TRUE, preferIntegerCoefficients: FALSE, vanilla: GGBasicTransformProc, --let the vanilla transform be the identity preserve: [X: 0.5, Y: 0.5] --this point stays fixed during scaling (viewer size change) ]]; popUpFont _ ImagerFont.Find["xerox/tiogafonts/helvetica10I", substituteQuietly]; bigFont _ ImagerFont.Scale[ImagerFont.Find["xerox/pressfonts/helvetica-brr", substituteQuietly], 72.0]; iconsFrom _ "Gargoyle.icons"; -- KAP. October 16, 1990 InitIcons[]; BEGIN -- BuildCursors 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 linesPreferredArray: 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]; linesPreferredCursor _ Cursors.NewCursor[bits: linesPreferredArray, hotX: -8, hotY: -5]; offCursor _ Cursors.NewCursor[bits: offArray, hotX: -8, hotY: -6]; END; Commander.Register[ key: "Gargoyle", proc: NewGGViewers, doc: "Create a Gargoyle Graphics Window", clientData: NIL ]; Commander.Register[ key: "GGIPToIP", proc: GGIPToIP, doc: "GGIPToIP  apply the named script to each of the named interpress files (after performing MergeIPEditable). A new file with -mod.ip at the end will be created corresponding to each original file", clientData: NIL ]; }; InitIcons: PUBLIC PROC = { holdThatTiger: BOOL _ GGUserProfile.GetHoldThatTiger[]; panelIconG _ Icons.NewIconFromFile[iconsFrom, 5]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/ noNameIconG _ Icons.NewIconFromFile[iconsFrom, IF holdThatTiger THEN 8 ELSE 1]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/ dirtyNoNameIconG _ Icons.NewIconFromFile[iconsFrom, IF holdThatTiger THEN 7 ELSE 0]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/ cleanIconG _ Icons.NewIconFromFile[iconsFrom, IF holdThatTiger THEN 10 ELSE 3]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/ dirtyIconG _ Icons.NewIconFromFile[iconsFrom, IF holdThatTiger THEN 9 ELSE 2]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/ }; GetIcons: PUBLIC PROC RETURNS [panelIcon, noNameIcon, dirtyNoNameIcon, cleanIcon, dirtyIcon: Icons.IconFlavor] = { RETURN[panelIconG, noNameIconG, dirtyNoNameIconG, cleanIconG, dirtyIconG]; }; popUpFont, bigFont: Imager.Font; -- initialized in Init actionAreaClass: BiScrollers.BiScrollerClass _ NIL; -- filled in by Init ggTipTable: TIPUser.TIPTable _ NIL; -- filled in by Init panelIconG: Icons.IconFlavor _ unInit; -- filled in by InitIcons noNameIconG: Icons.IconFlavor _ unInit; -- filled in by InitIcons dirtyNoNameIconG: Icons.IconFlavor _ unInit; -- filled in by InitIcons dirtyIconG: Icons.IconFlavor _ unInit; -- filled in by InitIcons cleanIconG: Icons.IconFlavor _ unInit; -- filled in by InitIcons iconsFrom: Rope.ROPE _ NIL; -- filled in by Init offCursor: Cursors.CursorType _ crossHairsCircle; -- proper value filled in by Init pointsPreferredCursor: Cursors.CursorType _ crossHairsCircle; -- proper value filled in by Init linesPreferredCursor: Cursors.CursorType _ crossHairsCircle; -- proper value filled in by Init Init[]; END.