SVSelectImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on March 11, 1987 4:43:56 pm PST
Contents: To provide a selection mechanism for Solidviews similar to the one found in Gargoyle. In particular, we maintain a list of the selected objects and offer generators and structure browsers to walk through this list.
DIRECTORY
GList, SVAssembly, SVScene, SVSceneTypes, SVSelect;
SVSelectImpl: CEDAR PROGRAM
IMPORTS GList, SVAssembly, SVScene
EXPORTS SVSelect
=
BEGIN
Slice: TYPE = SVSceneTypes.Slice;
AssemblyGenerator: TYPE = SVScene.AssemblyGenerator;
Scene: TYPE = SVSceneTypes.Scene;
SliceGenerator: TYPE = SVSceneTypes.SliceGenerator;
SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor;
SliceParts: TYPE = SVSceneTypes.SliceParts;
SelectionClass: TYPE = SVSelect.SelectionClass;
SliceDescriptorGenerator: TYPE = SVSceneTypes.SliceDescriptorGenerator;
SliceDescriptorGeneratorObj: TYPE = SVSceneTypes.SliceDescriptorGeneratorObj;
ChangeDonkeyTail: PROC [sliceD: SliceDescriptor, selectClass: SelectionClass] = {
SELECT selectClass FROM
normal => sliceD.slice.normalSelectedParts ← sliceD;
hot => sliceD.slice.hotSelectedParts ← sliceD;
active => sliceD.slice.activeSelectedParts ← sliceD;
ENDCASE;
};
NoDonkeyTail: PROC [slice: Slice, selectClass: SelectionClass] = {
SELECT selectClass FROM
normal => slice.normalSelectedParts ← NIL;
hot => slice.hotSelectedParts ← NIL;
active => slice.activeSelectedParts ← NIL;
ENDCASE;
};
SelectAll: PUBLIC PROC [scene: Scene, selectClass: SelectionClass] = {
g: AssemblyGenerator;
g ← SVScene.PrimAssembliesInScene[scene];
FOR slice: Slice ← SVScene.NextAssembly[g], SVScene.NextAssembly[g] UNTIL slice = NIL DO
SelectEntireSlice[slice, scene, selectClass];
ENDLOOP;
};
SelectSlice: PUBLIC PROC [sliceD: SliceDescriptor, scene: Scene, selectClass: SelectionClass] = {
oldSliceD, union: SliceDescriptor;
slice: Slice ← sliceD.slice;
IF SVAssembly.EmptyParts[sliceD] THEN RETURN;
oldSliceD ← FindSelectedSlice[slice, scene, selectClass];
IF oldSliceD#NIL THEN {
union ← SVAssembly.UnionParts[oldSliceD, sliceD];
DeselectSlice[slice, oldSliceD.parts, scene, selectClass]; -- throw away old selection
}
ELSE union ← sliceD;
IF selectClass = normal THEN union ← SVAssembly.AugmentParts[union, selectClass];
AppendSelection[scene, union, selectClass];
ChangeDonkeyTail[union, selectClass];
};
SelectEntireSlice: PUBLIC PROC [slice: Slice, scene: Scene, selectClass: SelectionClass] = {
allParts: SliceDescriptor ← SVAssembly.NewParts[slice, NIL, [0,0,0], slice];
SelectSlice[allParts, scene, selectClass];
};
DeselectAll: PUBLIC PROC [scene: Scene, selectClass: SelectionClass] = {
sliceD: SliceDescriptor;
FOR selected: LIST OF SliceDescriptor ← ListSelected[scene, selectClass], selected.rest UNTIL selected = NIL DO
sliceD ← selected.first;
NoDonkeyTail[sliceD.slice, selectClass];
ENDLOOP;
SetSelectedList[scene, NIL, selectClass];
};
DeselectAllAllClasses: PUBLIC PROC [scene: Scene] = {
DeselectAll[scene, normal];
DeselectAll[scene, active];
DeselectAll[scene, hot];
};
DeselectEntireSlice: PUBLIC PROC [slice: Slice, scene: Scene, selectClass: SelectionClass] = {
oldD: SliceDescriptor;
oldD ← FindSelectedSlice[slice, scene, selectClass];
IF oldD # NIL THEN {
DeleteSelection[scene, oldD, selectClass];
NoDonkeyTail[oldD.slice, selectClass];
};
};
DeselectSlice: PUBLIC PROC [slice: Slice, parts: SliceParts, scene: Scene, selectClass: SelectionClass] = {
oldD, newD, tempD: SliceDescriptor;
oldD ← FindSelectedSlice[slice, scene, selectClass];
IF oldD # NIL THEN {
tempD ← SVAssembly.DescriptorFromParts[slice, parts];
newD ← SVAssembly.DifferenceParts[oldD, tempD];
DeleteSelection[scene, oldD, selectClass];
NoDonkeyTail[oldD.slice, selectClass];
IF NOT SVAssembly.EmptyParts[newD] THEN {
IF selectClass = normal THEN newD ← SVAssembly.AugmentParts[newD, selectClass];
AppendSelection[scene, newD, selectClass];
ChangeDonkeyTail[newD, selectClass];
};
};
};
AppendSelection: PROC [scene: Scene, sliceD: SliceDescriptor, selectClass: SelectionClass] = {
Build the selection list in the proper order and keep it that way.
SELECT selectClass FROM
normal => scene.selected.normal ← NARROW[GList.Nconc[scene.selected.normal, LIST[sliceD]]];
hot => scene.selected.hot ← NARROW[GList.Nconc[scene.selected.hot, LIST[sliceD]]];
active => scene.selected.active ← NARROW[GList.Nconc[scene.selected.active, LIST[sliceD]]];
ENDCASE => ERROR;
};
Utilities
DeleteSelection: PROC [scene: Scene, sliceD: SliceDescriptor, selectClass: SelectionClass] = {
Deletes entity from list. If it is not on the list, do nothing.
SetSelectedList[scene,
NARROW[GList.DRemove[sliceD, ListSelected[scene, selectClass]]],
selectClass];
};
ListSelected: PUBLIC PROC [scene: Scene, selectClass: SelectionClass] RETURNS [selectedList: LIST OF SliceDescriptor] = {
SELECT selectClass FROM
normal => selectedList ← scene.selected.normal;
hot => selectedList ← scene.selected.hot;
active => selectedList ← scene.selected.active;
ENDCASE => ERROR;
};
OPERATIONS THAT ALTER THE SELECTED LISTS
AppendSelection: PROC [scene: Scene, entity: SliceDescriptor, selectClass: SelectionClass] = {
Build the selection list in the proper order and keep it that way.
SELECT selectClass FROM
normal => {
IF scene.selected.normal = NIL THEN {
scene.selected.normal ← LIST[entity];
scene.selected.normalPtr ← scene.selected.normal;
scene.selected.normalPtrValid ← TRUE;
}
ELSE IF scene.selected.normalPtrValid THEN {
scene.selected.normalPtr.rest ← LIST[entity];
scene.selected.normalPtr ← scene.selected.normalPtr.rest;
}
ELSE {
scene.selected.normalPtr ← LastSliceDescriptor[scene.selected.normal];
scene.selected.normalPtr.rest ← LIST[entity];
scene.selected.normalPtr ← scene.selected.normalPtr.rest;
scene.selected.normalPtrValid ← TRUE;
};
};
hot => {
IF scene.selected.hot = NIL THEN {
scene.selected.hot ← LIST[entity];
scene.selected.hotPtr ← scene.selected.hot;
scene.selected.hotPtrValid ← TRUE;
}
ELSE IF scene.selected.hotPtrValid THEN {
scene.selected.hotPtr.rest ← LIST[entity];
scene.selected.hotPtr ← scene.selected.hotPtr.rest;
}
ELSE {
scene.selected.hotPtr ← LastSliceDescriptor[scene.selected.hot];
scene.selected.hotPtr.rest ← LIST[entity];
scene.selected.hotPtr ← scene.selected.hotPtr.rest;
scene.selected.hotPtrValid ← TRUE;
};
};
active => {
IF scene.selected.active = NIL THEN {
scene.selected.active ← LIST[entity];
scene.selected.activePtr ← scene.selected.active;
scene.selected.activePtrValid ← TRUE;
}
ELSE IF scene.selected.activePtrValid THEN {
scene.selected.activePtr.rest ← LIST[entity];
scene.selected.activePtr ← scene.selected.activePtr.rest;
}
ELSE {
scene.selected.activePtr ← LastSliceDescriptor[scene.selected.active];
scene.selected.activePtr.rest ← LIST[entity];
scene.selected.activePtr ← scene.selected.activePtr.rest;
scene.selected.activePtrValid ← TRUE;
};
};
ENDCASE => ERROR;
};
LastSliceDescriptor: PROC [sliceDList: LIST OF SliceDescriptor] RETURNS [last: LIST OF SliceDescriptor] = {
FOR last ← sliceDList, last.rest UNTIL last.rest = NIL DO ENDLOOP;
};
SetSelectedList: PROC [scene: Scene, value: LIST OF SliceDescriptor, selectClass: SelectionClass] = {
SELECT selectClass FROM
normal => {
scene.selected.normal ← value;
scene.selected.normalPtrValid ← FALSE;
};
hot => {
scene.selected.hot ← value;
scene.selected.hotPtrValid ← FALSE;
};
active => {
scene.selected.active ← value;
scene.selected.activePtrValid ← FALSE;
};
ENDCASE => ERROR;
};
Enumerate Selected Objects
IsSelectedInPart: PUBLIC PROC [slice: Slice, scene: Scene, selectClass: SelectionClass] RETURNS [BOOL] = {
Returns TRUE if all or part of entity is selected. These are the cases:
1) entity is a slice. Some outline is selected all or in part.
2) entity is an outline. Some trajectory is selected all or in part.
3) entity is a trajectory. Some joint or segment is selected.
4) entity is a sequence. Some joint or segment is selected.
sliceD: SliceDescriptor;
sliceD ← FindSelectedSlice[slice, scene, selectClass];
RETURN[sliceD # NIL];
};
FindSelectedSlice: PUBLIC PROC [slice: Slice, scene: Scene, selectClass: SelectionClass] RETURNS [sliceD: SliceDescriptor] = {
SELECT selectClass FROM
normal => sliceD ← IF slice.normalSelectedParts = NIL THEN NIL ELSE slice.normalSelectedParts;
hot => sliceD ← IF slice.hotSelectedParts = NIL THEN NIL ELSE slice.hotSelectedParts;
active => sliceD ← IF slice.activeSelectedParts = NIL THEN NIL ELSE slice.activeSelectedParts;
ENDCASE => ERROR;
};
SelectedSlices: PUBLIC PROC [scene: Scene, selectClass: SelectionClass] RETURNS [sliceDescGen: SliceDescriptorGenerator] = {
sliceD: SliceDescriptor ← NIL;
ptr: LIST OF SliceDescriptor ← NIL;
sliceDescGen ← NEW[SliceDescriptorGeneratorObj];
FOR entityList: LIST OF SliceDescriptor ← ListSelected[scene, selectClass], entityList.rest UNTIL entityList = NIL DO
sliceD ← NARROW[entityList.first];
[sliceDescGen.list, ptr] ← AddSliceDescriptor[sliceD, sliceDescGen.list, ptr];
ENDLOOP;
};
AddSliceDescriptor: PROC [entity: SliceDescriptor, entityList, ptr: LIST OF SliceDescriptor] RETURNS [newList, newPtr: LIST OF SliceDescriptor] = {
IF ptr = NIL THEN {
IF NOT entityList = NIL THEN ERROR;
newPtr ← newList ← CONS[entity, NIL];
RETURN;
}
ELSE {
newList ← entityList;
ptr.rest ← CONS[entity, NIL];
newPtr ← ptr.rest;
};
};
NextSliceDescriptor: PUBLIC PROC [g: SliceDescriptorGenerator] RETURNS [next: SliceDescriptor] = {
IF g.list = NIL THEN RETURN[NIL]
ELSE {
next ← g.list.first;
g.list ← g.list.rest;
};
};
NextSlice: PUBLIC PROC [g: SliceDescriptorGenerator] RETURNS [next: Slice] = {
IF g.list = NIL THEN RETURN[NIL]
ELSE {
next ← g.list.first.slice;
g.list ← g.list.rest;
};
};
NoSelections: PUBLIC PROC [scene: Scene, selectClass: SelectionClass] RETURNS [BOOL] = {
SELECT selectClass FROM
normal => RETURN[scene.selected.normal = NIL];
hot => RETURN[scene.selected.hot = NIL];
active => RETURN[scene.selected.active = NIL];
ENDCASE => ERROR;
};
END.