GGUtilityImplC.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Pier, August 18, 1988 12:37:57 pm PDT
Bier, August 29, 1990 0:02 am PDT
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: BOOLFALSE] RETURNS [list: LIST OF Slice] = {
traverse the scene.entities from beginning (back) to end (front)
scene: Scene ← ggData.scene;
DoAddSliceToList: PROC [slice: Slice] RETURNS [done: BOOLFALSE] = {
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];
};
For GGMUserProfile
masterData: MasterData;
MasterData: TYPE = REF MasterDataObj;
MasterDataObj: TYPE = RECORD [
turboOn: BOOLFALSE,
junk: BOOLFALSE -- 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."];
};
Utilities for undo/history
RestoreSceneClean: PUBLIC PROC [scene: Scene, virginList: LIST OF Slice, virginMap: RefTab.Ref] = {
restores scene.entities to its original state as specified by the virginList and virginMap
found: BOOLFALSE;
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: REFNIL;
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
overlay original storage with virgin data from virginList
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: BOOLFALSE] RETURNS [virginList: LIST OF Slice, virginMap: RefTab.Ref] = {
ENABLE ABORTED => {IF virginMap#NIL THEN RefTab.Erase[virginMap]};
traverse the scene entities from beginning (back) to end (front), making a copy of the scene list from unselected slices AND copies of selected slices. Also, return a RefTab that maps the copies onto their originals. Used by history code. Calls must be properly synchronized by the caller to allow unambiguous traversal of the scene.
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: BOOLFALSE;
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: BOOLTRUE;
doUnlink: BOOLTRUE;
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.