<> <> <> <> DIRECTORY CedarProcess, Commander, FeedbackTypes, GGBasicTypes, GGCoreTypes, GGEvent, GGHistoryTypes, GGHistoryTypesOpaque, GGInterfaceTypes, GGModelTypes, GGMUserProfile, GGOutline, GGScene, GGSelect, GGSliceOps, GGUtility, IO, RefTab, Rope, UserProfile; GGUtilityImplC: CEDAR PROGRAM IMPORTS CedarProcess, Commander, GGScene, GGSelect, GGSliceOps, GGUtility, IO, RefTab, Rope, UserProfile EXPORTS GGHistoryTypes, GGUtility, GGMUserProfile = BEGIN Change: PUBLIC TYPE = GGHistoryTypesOpaque.Change; MsgRouter: TYPE = FeedbackTypes.MsgRouter; FontData: TYPE = GGModelTypes.FontData; GGData: TYPE = GGInterfaceTypes.GGData; GravityType: TYPE = GGInterfaceTypes.GravityType; HistoryEvent: TYPE = GGHistoryTypes.HistoryEvent; Line: TYPE = GGCoreTypes.Line; OverlapOrder: TYPE = GGUtility.OverlapOrder; Point: TYPE = GGBasicTypes.Point; Scene: TYPE = GGScene.Scene; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; Traj: TYPE = GGModelTypes.Traj; Vector: TYPE = GGBasicTypes.Vector; <<>> SequenceSubst: PUBLIC PROC [new, old: GGModelTypes.Sequence, expr: LIST OF GGModelTypes.Sequence] RETURNS [head: LIST OF GGModelTypes.Sequence _ NIL] = { tail, cons: LIST OF GGModelTypes.Sequence _ NIL; first: GGModelTypes.Sequence _ NIL; WHILE expr # NIL DO first _ expr.first; cons _ LIST[IF first = old THEN new ELSE first]; IF tail = NIL THEN head _ cons ELSE tail.rest _ cons; tail _ cons; expr _ expr.rest; ENDLOOP; }; OrderedSelectionList: PUBLIC PROC [ggData: GGData, order: OverlapOrder, andSelectEntire: BOOL _ FALSE] RETURNS [list: LIST OF Slice] = { <> scene: Scene _ ggData.scene; DoAddSliceToList: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { IF GGSelect.IsSelectedInPart[slice, scene, normal] THEN { list _ CONS[slice, list]; IF andSelectEntire THEN GGSelect.SelectEntireSlice[slice, scene, normal]; }; }; [] _ GGScene.WalkSlices[scene, first, DoAddSliceToList]; IF order=decr THEN list _ ReverseList[list]; }; ReverseList: PROC [list: LIST OF Slice] RETURNS [val: LIST OF Slice] = { val _ NIL; UNTIL list = NIL DO val _ CONS[list.first, val]; list _ list.rest; ENDLOOP; RETURN[val]; }; <> <<>> masterData: MasterData; MasterData: TYPE = REF MasterDataObj; MasterDataObj: TYPE = RECORD [ turboOn: BOOL _ FALSE, junk: BOOL _ FALSE -- records in Impls with one field kick up an Interpreter bug ]; LookAtProfile: PUBLIC UserProfile.ProfileChangedProc = { <<[reason: UserProfile.ProfileChangeReason]>> turboOn: BOOL _ UserProfile.Boolean[key: "Gargoyle.TurboOn", default: FALSE]; SetTurboOn[turboOn]; }; SetTurboOn: PUBLIC PROC [sense: BOOL] = { masterData.turboOn _ sense; }; GetTurboOn: PUBLIC PROC RETURNS [sense: BOOL] = { sense _ masterData.turboOn; }; GGTurboOn: Commander.CommandProc = { SetTurboOn[TRUE]; cmd.out.PutRope["Gargoyle turbo shape caching turned on."]; }; GGTurboOff: Commander.CommandProc = { SetTurboOn[FALSE]; cmd.out.PutRope["Gargoyle turbo shape caching turned off."]; }; <<>> <> RestoreSceneClean: PUBLIC PROC [scene: Scene, virginList: LIST OF Slice, virginMap: RefTab.Ref] = { <> found: BOOL _ FALSE; virginScene: Scene; restoredPtr: LIST OF Slice; restoredList: LIST OF Slice; [restoredList, restoredPtr] _ GGUtility.StartSliceList[]; FOR sliceList: LIST OF Slice _ virginList, sliceList.rest UNTIL sliceList = NIL DO original: REF _ NIL; nextSlice: Slice _ sliceList.first; -- candidate slice for new scene [found, original] _ RefTab.Fetch[virginMap, nextSlice]; -- is candidate mapped to original ? IF found THEN { originalSlice: Slice _ NARROW[original, Slice]; -- get original storage. May be trashed <> GGSliceOps.Restore[from: nextSlice, to: originalSlice]; nextSlice _ originalSlice; -- get ready to store }; nextSlice.parent _ NIL; -- in case it was a hole previously [restoredList, restoredPtr] _ GGUtility.AddSlice[nextSlice, restoredList, restoredPtr]; ENDLOOP; virginScene _ GGScene.CreateScene[restoredList]; -- fresh scene GGScene.SetScene[from: virginScene, to: scene]; -- wipes out selections in scene }; CopySceneClean: PUBLIC PROC [scene: Scene, copyAll: BOOL _ FALSE] RETURNS [virginList: LIST OF Slice, virginMap: RefTab.Ref] = { ENABLE ABORTED => {IF virginMap#NIL THEN RefTab.Erase[virginMap]}; <> CopyWithSelections: PROC [slice: Slice] RETURNS [copy: Slice] = { IF doSelections THEN GGSelect.SaveSelectionsInSliceAllClasses[slice, NIL]; -- scene argument no longer used copy _ GGSliceOps.Copy[slice].first; -- copy entire slice IF NOT RefTab.Insert[x: virginMap, key: copy, val: slice] THEN ERROR; }; virginPtr: LIST OF Slice; sceneList: LIST OF Slice _ GGScene.ListSlices[scene, first]; IF sceneList#NIL THEN { CedarProcess.CheckAbort[]; -- check self for aborted virginMap _ RefTab.Create[]; [virginList, virginPtr] _ GGUtility.StartSliceList[]; FOR sliceList: LIST OF Slice _ sceneList, sliceList.rest UNTIL sliceList = NIL DO slice: Slice _ sliceList.first; [virginList, virginPtr] _ GGUtility.AddSlice[IF copyAll OR GGSelect.IsSelectedInPart[slice, scene, normal] THEN CopyWithSelections[slice] ELSE slice, virginList, virginPtr]; CedarProcess.CheckAbort[]; -- check self for aborted ENDLOOP; }; }; UnlinkError: SIGNAL = CODE; UnlinkCapturedScene: PUBLIC PROC [historyEvent: HistoryEvent] = { IF historyEvent#NIL AND NOT Rope.Equal[historyEvent.name, "advance", FALSE] THEN SIGNAL UnlinkError; -- debugging check IF historyEvent#NIL AND historyEvent.subevents#NIL AND historyEvent.subevents.first#NIL THEN { found: BOOL _ FALSE; captureRef: REF Change _ historyEvent.subevents.first.historyData; captureData: REF Change.capture _ NARROW[captureRef]; FOR sliceList: LIST OF Slice _ captureData.virginData, sliceList.rest UNTIL sliceList = NIL DO found _ RefTab.Fetch[captureData.virginMap, sliceList.first].found; IF found AND doUnlink THEN GGSliceOps.Unlink[sliceList.first]; -- ASSERT: this slice appears only on the clean list and can be unlinked sliceList.first_NIL; ENDLOOP; IF captureData.virginMap#NIL THEN RefTab.Erase[captureData.virginMap]; }; }; doSelections: BOOL _ TRUE; doUnlink: BOOL _ TRUE; Init: PROC [] = { masterData _ NEW[MasterDataObj]; UserProfile.CallWhenProfileChanges[LookAtProfile]; Commander.Register["GGTurboOn", GGTurboOn, "turns on Imager.Object caching to speed up Gargoyle refresh on black and white displays"]; Commander.Register["GGTurboOff", GGTurboOff, "turns off Imager.Object caching to speed up Gargoyle refresh on black and white displays"]; }; Init[]; END.