GGUtilityImplC.mesa
Copyright Ó 1987, 1992 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: BOOL ¬ FALSE] 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: 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];
};
For GGMUserProfile
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."];
};
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: 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
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: BOOL ¬ FALSE] 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: 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.