DIRECTORY GGError, GGModelTypes, GGObjects, GGInterfaceTypes, GGSelect, GGUtility, Rosary; GGSelectImpl: CEDAR PROGRAM IMPORTS GGError, GGObjects, GGUtility, Rosary EXPORTS GGSelect = BEGIN Cluster: TYPE = GGModelTypes.Cluster; EntityGenerator: TYPE = REF EntityGeneratorObj; EntityGeneratorObj: TYPE = GGModelTypes.EntityGeneratorObj; Joint: TYPE = GGModelTypes.Joint; JointPair: TYPE = GGModelTypes.JointPair; JointGenerator: TYPE = GGModelTypes.JointGenerator; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Outline: TYPE = GGModelTypes.Outline; Segment: TYPE = GGModelTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; SelectionClass: TYPE = GGInterfaceTypes.SelectionClass; Sequence: TYPE = REF SequenceObj; SequenceObj: TYPE = GGModelTypes.SequenceObj; SequenceGenerator: TYPE = REF SequenceGeneratorObj; SequenceGeneratorObj: TYPE = GGModelTypes.SequenceGeneratorObj; Traj: TYPE = GGModelTypes.Traj; TrajGenerator: TYPE = REF TrajGeneratorObj; TrajGeneratorObj: TYPE = GGModelTypes.TrajGeneratorObj; IsOnList: PROC [entity: REF ANY, gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [BOOL] = { RETURN[GGUtility.IsMember[entity, ListSelected[gargoyleData, selectClass]]]; }; AncestorOnList: PROC [entity: REF ANY, gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [BOOL] = { IF entity = NIL THEN RETURN[FALSE]; IF IsOnList[entity, gargoyleData, selectClass] THEN RETURN[TRUE]; WITH entity SELECT FROM cluster: Cluster => RETURN[AncestorOnList[cluster.parent, gargoyleData, selectClass]]; outline: Outline => RETURN[AncestorOnList[outline.parent, gargoyleData, selectClass]]; traj: Traj => RETURN[AncestorOnList[traj.outline, gargoyleData, selectClass]]; seq: Sequence => RETURN[AncestorOnList[seq.traj, gargoyleData, selectClass]]; ENDCASE => ERROR; }; FindTheSequence: PROC [traj: Traj, gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [seq: Sequence] = { FOR l: LIST OF REF ANY _ ListSelected[gargoyleData, selectClass], l.rest UNTIL l = NIL DO IF ISTYPE[l.first, Sequence] THEN { thisSeq: Sequence _ NARROW[l.first]; IF thisSeq.traj = traj THEN RETURN[thisSeq]; }; ENDLOOP; RETURN[NIL]; }; GetAnyAncestor: PROC [entity: REF ANY, gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [ancestor: REF ANY] = { IF entity = NIL THEN ERROR; IF IsOnList[entity, gargoyleData, selectClass] THEN RETURN[entity]; WITH entity SELECT FROM cluster: Cluster => RETURN[GetAnyAncestor[cluster.parent, gargoyleData, selectClass]]; outline: Outline => RETURN[GetAnyAncestor[outline.parent, gargoyleData, selectClass]]; traj: Traj => RETURN[GetAnyAncestor[traj.outline, gargoyleData, selectClass]]; seq: Sequence => RETURN[GetAnyAncestor[seq.traj, gargoyleData, selectClass]]; ENDCASE => ERROR; }; ListComponentsOnList: PROC [entity: REF ANY, gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [components: LIST OF REF ANY] = { components _ NIL; WITH entity SELECT FROM cluster: Cluster => { entityGen: EntityGenerator; entityGen _ GGObjects.EntitiesInCluster[cluster]; FOR child: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL child = NIL DO IF IsOnList[child, gargoyleData, selectClass] THEN components _ CONS[child, components] ELSE components _ GGUtility.AppendList[ListComponentsOnList[child, gargoyleData, selectClass], components]; ENDLOOP; }; outline: Outline => { trajGen: TrajGenerator; thisSeq: Sequence; trajGen _ GGObjects.TrajsInOutline[outline]; FOR child: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL child = NIL DO thisSeq _ FindTheSequence[child, gargoyleData, selectClass]; IF thisSeq # NIL THEN components _ CONS[thisSeq, components]; ENDLOOP; }; seq: Sequence => ERROR; -- sequences cannot be divided further ENDCASE => ERROR; }; SetComponentSelectedFields: PROC [entity: REF ANY, selected: BOOL, gargoyleData: GargoyleData, selectClass: SelectionClass] = { WITH entity SELECT FROM cluster: Cluster => { entityGen: EntityGenerator; SetClusterField[cluster, selected, selectClass]; entityGen _ GGObjects.EntitiesInCluster[cluster]; FOR child: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL child = NIL DO SetComponentSelectedFields[child, selected, gargoyleData, selectClass]; ENDLOOP; }; outline: Outline => { trajGen: TrajGenerator; SetOutlineField[outline, selected, selectClass]; trajGen _ GGObjects.TrajsInOutline[outline]; FOR child: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL child = NIL DO joint: Joint; seg: Segment; FOR i: NAT IN [0..GGObjects.HiJoint[child]] DO joint _ NARROW[Rosary.Fetch[child.joints, i]]; SetJointField[joint, selected, selectClass]; ENDLOOP; FOR i: NAT IN [0..GGObjects.HiSegment[child]] DO seg _ NARROW[Rosary.Fetch[child.segments, i]]; SetSegmentField[seg, selected, selectClass]; ENDLOOP; ENDLOOP; }; seq: Sequence => { joint: Joint; jointGen: JointGenerator; segGen: SegmentGenerator; SetSequenceField[seq, selected, selectClass]; -- this field is pretty useless. jointGen _ GGObjects.JointsInSequence[seq]; FOR i: INT _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL i = -1 DO joint _ NARROW[Rosary.Fetch[seq.traj.joints, i]]; SetJointField[joint, selected, selectClass]; ENDLOOP; segGen _ GGObjects.SegmentsInSequence[seq]; FOR seg: Segment _ GGObjects.NextSegment[segGen], GGObjects.NextSegment[segGen] UNTIL seg = NIL DO SetSegmentField[seg, selected, selectClass]; ENDLOOP; }; ENDCASE => ERROR; }; NotYetImplemented: PUBLIC SIGNAL = CODE; SelectCluster: PUBLIC PROC [cluster: Cluster, gargoyleData: GargoyleData, selectClass: SelectionClass] = { ERROR NotYetImplemented; }; SelectOutline: PUBLIC PROC [outline: Outline, gargoyleData: GargoyleData, selectClass: SelectionClass] = { components: LIST OF REF ANY; IF AncestorOnList[outline, gargoyleData, selectClass] THEN { GGError.Append["Outline already selected. Ignored.",oneLiner]; GGError.Blink[]; RETURN; -- Do nothing }; components _ ListComponentsOnList[outline, gargoyleData, selectClass]; IF components # NIL THEN { FOR seqList: LIST OF REF ANY _ components, seqList.rest UNTIL seqList = NIL DO DeselectEntity[seqList.first, gargoyleData, selectClass]; ENDLOOP; }; AppendSelection[gargoyleData, outline, selectClass]; SetComponentSelectedFields[outline, TRUE, gargoyleData, selectClass]; }; SelectTraj: PUBLIC PROC [traj: Traj, gargoyleData: GargoyleData, selectClass: SelectionClass] = { oldSeq, wholeSeq: Sequence; oldSeq _ FindTheSequence[traj, gargoyleData, selectClass]; IF oldSeq # NIL THEN { DeselectSequence[oldSeq, gargoyleData, selectClass]; }; IF AncestorOnList[traj, gargoyleData, selectClass] THEN { GGError.Append["Trajectory already selected. Ignored.", oneLiner]; RETURN; -- Do nothing }; wholeSeq _ GGObjects.CreateCompleteSequence[traj]; AppendSelection[gargoyleData, wholeSeq, selectClass]; SetComponentSelectedFields[wholeSeq, TRUE, gargoyleData, selectClass]; }; EntireTrajectory: PROC [seq: Sequence] RETURNS [BOOL] = { segGen: SegmentGenerator _ GGObjects.SegmentsInSequence[seq]; RETURN[segGen.toGo = seq.traj.segCount]; }; SelectSequence: PUBLIC PROC [seq: Sequence, gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [union, newMinusOld: Sequence] = { jointGen: JointGenerator; segGen: SegmentGenerator; joint: Joint; oldSeq: Sequence; oldSeq _ FindTheSequence[seq.traj, gargoyleData, selectClass]; IF oldSeq # NIL THEN { [union, newMinusOld] _ GGObjects.CombineSequences[seq, oldSeq]; IF EntireTrajectory[union] THEN union.all _ TRUE; DeselectSequence[oldSeq, gargoyleData, selectClass]; AppendSelection[gargoyleData, union, selectClass]; jointGen _ GGObjects.JointsInSequence[union]; segGen _ GGObjects.SegmentsInSequence[union]; } ELSE { IF EntireTrajectory[seq] THEN seq.all _ TRUE; AppendSelection[gargoyleData, seq, selectClass]; union _ seq; newMinusOld _ seq; jointGen _ GGObjects.JointsInSequence[seq]; segGen _ GGObjects.SegmentsInSequence[seq]; }; FOR jointNum: INT _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL jointNum = -1 DO joint _ NARROW[Rosary.Fetch[seq.traj.joints, jointNum]]; SetJointField[joint, TRUE, selectClass]; ENDLOOP; FOR seg: Segment _ GGObjects.NextSegment[segGen], GGObjects.NextSegment[segGen] UNTIL seg = NIL DO SetSegmentField[seg, TRUE, selectClass]; ENDLOOP; }; SelectEntity: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData, selectClass: SelectionClass] = { WITH entity SELECT FROM cluster: Cluster => SelectCluster[cluster, gargoyleData, selectClass]; outline: Outline => SelectOutline[outline, gargoyleData, selectClass]; traj: Traj => SelectTraj[traj, gargoyleData, selectClass]; seq: Sequence => [----,----] _ SelectSequence[seq, gargoyleData, selectClass]; ENDCASE => ERROR; }; SelectAll: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] = { entityGen: EntityGenerator; entityGen _ GGObjects.TopLevelEntities[gargoyleData.scene]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO SelectEntity[entity, gargoyleData, selectClass]; ENDLOOP; }; DeleteSelection: PRIVATE PROC [gargoyleData: GargoyleData, entity: REF ANY, selectClass: SelectionClass] = { SetSelectedList[gargoyleData, GGUtility.DeleteEntityFromList[entity, ListSelected[gargoyleData, selectClass]], selectClass]; }; DeselectCluster: PUBLIC PROC [cluster: Cluster, gargoyleData: GargoyleData, selectClass: SelectionClass] = { IF NOT IsSelected[cluster, gargoyleData, selectClass] THEN RETURN; ERROR NotYetImplemented; }; DeselectOutline: PUBLIC PROC [outline: Outline, gargoyleData: GargoyleData, selectClass: SelectionClass] = { components: LIST OF REF ANY; IF AncestorOnList[outline.parent, gargoyleData, selectClass] THEN { GGError.Append["Deselecting Parts of clusters not yet implemented.", oneLiner]; GGError.Blink[]; ERROR; }; IF IsSelected[outline, gargoyleData, selectClass] THEN { DeleteSelection[gargoyleData, outline, selectClass]; SetComponentSelectedFields[outline, FALSE, gargoyleData, selectClass]; } ELSE { -- make sure that all descendants of outline are removed from the selected list and have their component fields cleared components _ ListComponentsOnList[outline, gargoyleData, selectClass]; IF components # NIL THEN { FOR seqList: LIST OF REF ANY _ components, seqList.rest UNTIL seqList = NIL DO DeselectEntity[seqList.first, gargoyleData, selectClass]; ENDLOOP; }; }; }; DeselectSequence: PUBLIC PROC [seq: Sequence, gargoyleData: GargoyleData, selectClass: SelectionClass] = { jointGen: JointGenerator; joint: Joint; oldSeq, oldMinusNew: Sequence; oldSeq _ FindTheSequence[seq.traj, gargoyleData, selectClass]; IF oldSeq # NIL THEN { [----, oldMinusNew] _ GGObjects.CombineSequences[oldSeq, seq]; DeleteSelection[gargoyleData, oldSeq, selectClass]; IF oldMinusNew.parts # NIL THEN AppendSelection[gargoyleData, oldMinusNew, selectClass]; } ELSE RETURN; -- it wasn't selected in the first place FOR jointNum: NAT IN [0..GGObjects.HiJoint[seq.traj]] DO joint _ NARROW[Rosary.Fetch[seq.traj.joints, jointNum]]; SetJointField[joint, FALSE, selectClass]; ENDLOOP; jointGen _ GGObjects.JointsInSequence[oldMinusNew]; FOR jointNum: INT _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL jointNum = -1 DO joint _ NARROW[Rosary.Fetch[seq.traj.joints, jointNum]]; SetJointField[joint, TRUE, selectClass]; ENDLOOP; }; DeselectEntity: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData, selectClass: SelectionClass] = { WITH entity SELECT FROM cluster: Cluster => DeselectCluster[cluster, gargoyleData, selectClass]; outline: Outline => DeselectOutline[outline, gargoyleData, selectClass]; seq: Sequence => DeselectSequence[seq, gargoyleData, selectClass]; ENDCASE => ERROR; }; DeselectAll: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] = { FOR selected: LIST OF REF ANY _ ListSelected[gargoyleData, selectClass], selected.rest UNTIL selected = NIL DO SetComponentSelectedFields[selected.first, FALSE, gargoyleData, selectClass]; ENDLOOP; SetSelectedList[gargoyleData, NIL, selectClass]; }; ListSelected: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [selectedList: LIST OF REF ANY] = { SELECT selectClass FROM normal => selectedList _ gargoyleData.selected.normal; copy => selectedList _ gargoyleData.selected.copy; hot => selectedList _ gargoyleData.selected.hot; active => selectedList _ gargoyleData.selected.active; ENDCASE => ERROR; }; ListSelectedSequences: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [selectedList: LIST OF Sequence] = { seq: Sequence; selectedList _ NIL; FOR entityList: LIST OF REF ANY _ ListSelected[gargoyleData, selectClass], entityList.rest UNTIL entityList = NIL DO IF ISTYPE[entityList.first, Sequence] THEN { seq _ NARROW[entityList.first]; selectedList _ CONS[seq, selectedList]; }; ENDLOOP; }; SetClusterField: PROC [cluster: Cluster, selected: BOOL, selectClass: SelectionClass] = { SELECT selectClass FROM normal => cluster.selected.normal _ selected; copy => cluster.selected.copy _ selected; hot => cluster.selected.hot _ selected; active => cluster.selected.active _ selected; ENDCASE; }; SetOutlineField: PROC [outline: Outline, selected: BOOL, selectClass: SelectionClass] = { SELECT selectClass FROM normal => outline.selected.normal _ selected; copy => outline.selected.copy _ selected; hot => outline.selected.hot _ selected; active => outline.selected.active _ selected; ENDCASE; }; SetSequenceField: PROC [seq: Sequence, selected: BOOL, selectClass: SelectionClass] = { SELECT selectClass FROM normal => seq.selected.normal _ selected; copy => seq.selected.copy _ selected; hot => seq.selected.hot _ selected; active => seq.selected.active _ selected; ENDCASE; }; SetJointField: PROC [joint: Joint, selected: BOOL, selectClass: SelectionClass] = { SELECT selectClass FROM normal => joint.selected.normal _ selected; copy => joint.selected.copy _ selected; hot => joint.selected.hot _ selected; active => joint.selected.active _ selected; ENDCASE; }; SetSegmentField: PROC [seg: Segment, selected: BOOL, selectClass: SelectionClass] = { SELECT selectClass FROM normal => seg.selected.normal _ selected; copy => seg.selected.copy _ selected; hot => seg.selected.hot _ selected; active => seg.selected.active _ selected; ENDCASE; }; AppendSelection: PROC [gargoyleData: GargoyleData, entity: REF ANY, selectClass: SelectionClass] = { SELECT selectClass FROM normal => gargoyleData.selected.normal _ CONS[entity, gargoyleData.selected.normal]; copy => gargoyleData.selected.copy _ CONS[entity, gargoyleData.selected.copy]; hot => gargoyleData.selected.hot _ CONS[entity, gargoyleData.selected.hot]; active => gargoyleData.selected.active _ CONS[entity, gargoyleData.selected.active]; ENDCASE => ERROR; }; SetSelectedList: PROC [gargoyleData: GargoyleData, value: LIST OF REF ANY, selectClass: SelectionClass] = { SELECT selectClass FROM normal => gargoyleData.selected.normal _ value; copy => gargoyleData.selected.copy _ value; hot => gargoyleData.selected.hot _ value; active => gargoyleData.selected.active _ value; ENDCASE => ERROR; }; IsSelected: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [BOOL] = { WITH entity SELECT FROM cluster: Cluster => { SELECT selectClass FROM normal => RETURN[cluster.selected.normal]; copy => RETURN[cluster.selected.copy]; hot => RETURN[cluster.selected.hot]; active => RETURN[cluster.selected.active]; ENDCASE => ERROR; }; outline: Outline => { SELECT selectClass FROM normal => RETURN[outline.selected.normal]; copy => RETURN[outline.selected.copy]; hot => RETURN[outline.selected.hot]; active => RETURN[outline.selected.active]; ENDCASE => ERROR; }; traj: Traj => { seq: Sequence _ FindSelectedSequence[traj, gargoyleData, selectClass]; IF seq = NIL THEN { parent: Outline _ GGObjects.OutlineOfTraj[traj]; RETURN[IsSelected[parent, gargoyleData, selectClass]]; }; RETURN[seq.all]; }; seq: Sequence => { SELECT selectClass FROM normal => RETURN[seq.selected.normal]; copy => RETURN[seq.selected.copy]; hot => RETURN[seq.selected.hot]; active => RETURN[seq.selected.active]; ENDCASE => ERROR; }; joint: Joint => { SELECT selectClass FROM normal => RETURN[joint.selected.normal]; copy => RETURN[joint.selected.copy]; hot => RETURN[joint.selected.hot]; active => RETURN[joint.selected.active]; ENDCASE => ERROR; }; seg: Segment => { SELECT selectClass FROM normal => RETURN[seg.selected.normal]; copy => RETURN[seg.selected.copy]; hot => RETURN[seg.selected.hot]; active => RETURN[seg.selected.active]; ENDCASE => ERROR; }; ENDCASE => ERROR; }; IsSelectedInPart: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [BOOL] = { WITH entity SELECT FROM cluster: Cluster => { IF IsSelected[cluster, gargoyleData, selectClass] THEN RETURN[TRUE]; ERROR NotYetImplemented; }; outline: Outline => { trajGen: TrajGenerator; IF IsSelected[outline, gargoyleData, selectClass] THEN RETURN[TRUE]; trajGen _ GGObjects.TrajsInOutline[outline]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO IF IsSelectedInPart[traj, gargoyleData, selectClass] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; traj: Traj => { seq: Sequence; seq _ FindSelectedSequence[traj, gargoyleData, selectClass]; RETURN[seq # NIL]; }; seq: Sequence => { selSeq: Sequence; selSeq _ FindSelectedSequence[seq.traj, gargoyleData, selectClass]; IF selSeq = seq THEN RETURN[TRUE]; IF selSeq = NIL THEN RETURN[FALSE]; RETURN[GGObjects.SequencesOverlap[seq, selSeq]]; }; joint: Joint => { RETURN[IsSelected[joint, gargoyleData, selectClass]]; }; seg: Segment => { RETURN[IsSelected[seg, gargoyleData, selectClass]]; }; ENDCASE => ERROR; }; NoSelections: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [BOOL] = { SELECT selectClass FROM normal => RETURN[gargoyleData.selected.normal = NIL]; copy => RETURN[gargoyleData.selected.copy = NIL]; hot => RETURN[gargoyleData.selected.hot = NIL]; active => RETURN[gargoyleData.selected.active = NIL]; ENDCASE => ERROR; }; ListSelectedDescendants: PUBLIC PROC [entity: REF ANY, gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [components: LIST OF REF ANY] = { components _ NIL; WITH entity SELECT FROM cluster: Cluster => { entityGen: EntityGenerator; entityGen _ GGObjects.EntitiesInCluster[cluster]; FOR child: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL child = NIL DO IF IsSelected[child, gargoyleData, selectClass] THEN components _ CONS[child, components] ELSE components _ GGUtility.AppendList[ListComponentsOnList[child, gargoyleData, selectClass], components]; ENDLOOP; }; outline: Outline => { trajGen: TrajGenerator; trajGen _ GGObjects.TrajsInOutline[outline]; FOR child: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL child = NIL DO IF IsSelected[child, gargoyleData, selectClass] THEN components _ CONS[child, components] ELSE components _ GGUtility.AppendList[ListComponentsOnList[child, gargoyleData, selectClass], components]; ENDLOOP; }; traj: Traj => { FOR guess: LIST OF REF ANY _ ListSelected[gargoyleData, selectClass], guess.rest UNTIL guess = NIL DO IF ISTYPE[guess.first, Sequence] THEN { seq: Sequence _ NARROW[guess.first]; IF seq.traj = traj THEN components _ CONS[seq, components]; }; ENDLOOP; }; seq: Sequence => ERROR NotYetImplemented; ENDCASE => ERROR; }; FindSelectedSequence: PUBLIC PROC [traj: Traj, gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [seq: Sequence] = { seq _ NIL; FOR guess: LIST OF REF ANY _ ListSelected[gargoyleData, selectClass], guess.rest UNTIL guess = NIL DO IF ISTYPE[guess.first, Sequence] THEN { seq _ NARROW[guess.first]; IF seq.traj = traj THEN RETURN[seq]; }; ENDLOOP; RETURN[NIL]; }; SelectedEntities: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [selectedGen: EntityGenerator] = { selectedGen _ NEW[EntityGeneratorObj]; selectedGen.list _ ListSelected[gargoyleData, selectClass]; }; SelectedSequences: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [seqGen: SequenceGenerator] = { seq: Sequence; seqGen _ NEW[SequenceGeneratorObj]; seqGen.list _ NIL; FOR entityList: LIST OF REF ANY _ ListSelected[gargoyleData, selectClass], entityList.rest UNTIL entityList = NIL DO IF ISTYPE[entityList.first, Sequence] THEN seq _ NARROW[entityList.first]; seqGen.list _ CONS[seq, seqGen.list]; ENDLOOP; }; END. ΒGGSelectImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last edited by Bier on November 7, 1985 11:03:52 pm PST Contents: Procedures dealing selecting and deselecting objects, including both selection actions and selection feedback. Implementation Notes: The Selection mechanism maintains two "structures" which must be kept consistent. The first is a list of selected entities: gargoyleData.selectedEntities. The second is the set of "selected" fields in each of the selected objects. The following types of entities can appear on gargoyleData.selectedEntities: clusters, outlines, trajectories, and sequences. A sequence can represent a single selected joint or a sequence of selected joints. No support for selected control points is provided yet. "selected" fields are found in clusters, outlines, trajectories, sequences, and joints. The following invariants should be maintained: 1) If an entity is on the selected list, its selected field, and all of the selected fields of its components should be TRUE. 2) If an entity is on the selected list, none of its components should be on the selected list. 3) If a sequence is on the selected list, all of the selected fields of its joints should be TRUE. 4) If an entity is not on the selected list, and none of its ancestors are, its selected field should be FALSE. 5) No entity may be on the selection list twice. 6) If several sequences for the same trajectory are selected, they must not overlap. These invariants will be maintained with the help of these procedures: IsOnList, AncestorOnList, ListComponentsOnList, SetComponentSelectedFields, ListOtherSequencesOnList PUBLIC Procedures outline is now selected. This overrides any selections on outline's parts. Check to see if any of the outline's parts are selected. traj is now selected. This overrides any selections on traj's parts. Check to see if any of the trajectory's parts are selected. Outline is now deselected. If any ancestors of outline are selected, they are not (selected in entirety) anymore. For now, we just check that this isn't true. This procedure should also be updated to work when outline is not selected in entirety. DeselectTraj: PUBLIC PROC [traj: Traj, gargoyleData: GargoyleData, selectClass: SelectionClass] = { traj is now deselected. If any ancestors of traj are selected, they are not (selected in entirety) anymore. For now, we just check that this isn't true. This procedure should also be updated to work when traj is not selected in entirety. IF NOT IsSelected[traj, selectClass] THEN RETURN; IF AncestorOnList[traj.outline, gargoyleData, selectClass] THEN { GGError.Append["Deselecting Parts of outlines not yet implemented.", oneLiner]; GGError.Blink[]; ERROR; }; DeleteSelection[gargoyleData, traj, selectClass]; SetComponentSelectedFields[traj, FALSE, gargoyleData, selectClass]; }; traj: Traj => DeselectTraj[traj, gargoyleData, selectClass]; Clear all flags that indicate the selection of each object. SelectedTrajs: PUBLIC PROC [gargoyleData: GargoyleData, selectClass: SelectionClass] RETURNS [trajGen: TrajGenerator] = { This is rather inefficient for large scenes. allGen: TrajGenerator _ GGObjects.TrajsInScene[gargoyleData.scene]; trajGen _ NEW[TrajGeneratorObj]; trajGen.list _ NIL; FOR traj: Traj _ GGObjects.NextTraj[allGen], GGObjects.NextTraj[allGen] UNTIL traj = NIL DO IF IsSelected[traj, selectClass] THEN trajGen.list _ CONS[traj, trajGen.list]; ENDLOOP; }; This can be sped up by keeping separate lists for the different types of selected object. Operations which dispatch on the SelectionClass: SetTrajField: PROC [traj: Traj, selected: BOOL, selectClass: SelectionClass] = { SELECT selectClass FROM normal => traj.selected.normal _ selected; copy => traj.selected.copy _ selected; hot => traj.selected.hot _ selected; active => traj.selected.active _ selected; ENDCASE; }; A trajectory is selected if either: 1) A sequence representing it appears on the selected list, or 2) Its parent outline is selected. Selected bits for trajectories have been abandoned for now. Returns TRUE if all or part of entity is selected. These are the cases: 1) entity is a cluster. 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 (not yet implemented). Otherwise, search its children. This only finds partially selected trajectories. Κ‹˜head1™Icodešœ Οmœ1™Jšžœžœ˜J˜J˜—˜J˜—š Ÿœžœ žœžœ žœ>˜Jšžœžœž˜šœ˜J˜Jšœ0˜0Jšœ1˜1š žœžœžœDžœ žœž˜jJšœG˜G—Jšžœ˜J˜—šœ˜Jšœ˜Jšœ0˜0Jšœ,˜,šžœHžœ žœž˜_J˜ J˜ šžœžœžœž˜.Jšœžœ ˜.Jšœ,˜,—Jšžœ˜šžœžœžœ!ž˜0Jšœžœ"˜.Jšœ,˜,—Jšžœ˜—Jšžœ˜J˜—šœ˜J˜ J˜J˜JšœN˜NJšœ+˜+šžœžœ@žœž˜YJšœžœ#˜1Jšœ,˜,—Jšžœ˜Jšœ+˜+šžœMžœžœž˜bJšœ,˜,—Jšžœ˜J˜—Jšžœžœ˜J˜J˜—J˜J™Jšœžœžœžœ˜(J™J™J™šŸ œžœžœP˜jJšžœ˜J˜J˜—šŸ œžœžœP˜jJ™KJšœ ž œžœ˜šžœ4žœ˜˜>J˜Jšžœ  ˜J˜—Jšœ8™8JšœF˜Fšžœžœžœ˜šžœ žœžœžœžœžœ žœž˜NJšœ9˜9—Jšžœ˜J˜—Jšœ4˜4Jšœ$žœ˜EJ˜J™—šŸ œžœžœJ˜aJ™EJšœ˜šœ:˜:J™;—šžœ žœžœ˜Jšœ4˜4J˜—šžœ1žœ˜9JšœB˜BJšžœ  ˜J˜—J˜2JšŸœ&˜5Jšœ%žœ˜FJ˜J™—šŸœžœžœžœ˜9Jšœ=˜=Jšžœ"˜(J˜J˜—šŸœžœžœJžœ#˜J˜J˜J˜ Jšœ˜Jšœ>˜>šžœ žœžœ˜Jšœ?˜?Jšžœžœ žœ˜1Jšœ4˜4Jšœ2˜2Jšœ-˜-Jšœ-˜-J˜—šžœ˜Jšžœžœ žœ˜-Jšœ0˜0Jšœ ˜ Jšœ˜Jšœ+˜+Jšœ+˜+J˜—šžœ žœ@žœž˜gJšœžœ*˜8Jšœžœ˜(—Jšžœ˜šžœMžœžœž˜bJšœžœ˜(—Jšžœ˜J˜J˜—šŸ œž œ žœžœ>˜hJšžœžœž˜JšœF˜FJšœF˜FJšœ:˜:JšœN˜NJšžœžœ˜J˜J˜—šŸ œž œ>˜TJ˜Jšœ;˜;š žœ žœžœDžœ žœž˜lJšœ0˜0—Jšžœ˜J˜J˜—J˜šŸœž œ&žœžœ"˜lšœ˜JšœP˜PJšœ ˜ —J˜J˜—šŸœžœžœP˜lJšžœžœ0žœžœ˜BJšžœ˜J˜J˜—šŸœžœžœP˜lJšœω™ωJš œ žœžœžœžœ˜šžœ;žœ˜CJšœO˜OJ˜Jšžœ˜J˜—šžœ0žœ˜8Jšœ4˜4Jšœ$žœ˜FJ˜—šžœ w˜~JšœF˜Fšžœžœžœ˜šžœ žœžœžœžœžœ žœž˜NJšœ9˜9—Jšžœ˜J˜—J˜—J˜J™—šŸ œžœžœJ™cJšœπ™πJšžœžœžœžœ™1šžœ9žœ™AJšœO™OJ™Jšžœ™J™—Jšœ1™1Jšœ!žœ™CJ™J™—šŸœžœžœM˜jJ˜J˜ Jšœ˜Jšœ>˜>šžœ žœžœ˜Jšœ œ9˜>Jšœ3˜3šžœžœž˜Jšœ8˜8—J˜—Jšžœžœ+˜6šžœ žœžœ"ž˜8Jšœžœ*˜8Jšœžœ˜)—Jšžœ˜Jšœ3˜3šžœ žœ@žœž˜gJšœžœ*˜8Jšœžœ˜(—Jšžœ˜J˜J˜J˜—š Ÿœžœžœ žœžœ>˜jJšžœžœž˜JšœH˜HJšœH˜HJšœ<™˜VJ™;šžœ žœžœžœžœ:žœ žœž˜nJšœ+žœ˜M—Jšžœ˜Jšœžœ˜0J˜J˜—šŸ œžœžœ;žœžœžœžœžœ˜Jšœ˜Jšœ6˜6Jšœ2˜2Jšœ0˜0Jšœ6˜6Jšžœžœ˜J˜J˜—šŸ œžœžœ;žœ™yJ™,JšœC™CJšœ žœ™ Jšœžœ™šžœEžœžœž™[Jšžœžœžœ™N—Jšžœ™J™J™—š Ÿœžœžœ;žœžœžœ˜‰J™YJšœ˜Jšœžœ˜šžœ žœžœžœžœ<žœžœž˜tšžœžœžœ˜,Jšœžœ˜Jšœžœ˜'J˜——Jšžœ˜J˜—˜J˜—Jšœ0™0J™šŸœžœžœ#˜ZJšžœ ž˜Jšœ-˜-Jšœ)˜)Jšœ'˜'Jšœ-˜-Jšžœ˜J˜—šŸœžœžœ#˜ZJšžœ ž˜Jšœ-˜-Jšœ)˜)Jšœ'˜'Jšœ-˜-Jšžœ˜J˜—šŸ œžœžœ#™QJšžœ ž™Jšœ*™*Jšœ&™&Jšœ$™$Jšœ*™*Jšžœ™J™—šŸœžœžœ#˜XJšžœ ž˜Jšœ)˜)Jšœ%˜%Jšœ#˜#Jšœ)˜)Jšžœ˜J˜—šŸ œžœžœ#˜TJšžœ ž˜Jšœ+˜+Jšœ'˜'Jšœ%˜%Jšœ+˜+Jšžœ˜J˜—šŸœžœžœ#˜VJšžœ ž˜Jšœ)˜)Jšœ%˜%Jšœ#˜#Jšœ)˜)Jšžœ˜J˜—J™šŸœžœ&žœžœ"˜dJšžœ ž˜Jšœ)žœ'˜TJšœ%žœ%˜NJšœ#žœ$˜KJšœ)žœ'˜TJšžœžœ˜J˜J˜—š Ÿœžœ%žœžœžœžœ"˜kJšžœ ž˜Jšœ/˜/Jšœ+˜+Jšœ)˜)Jšœ/˜/Jšžœžœ˜J˜J˜—J˜šŸ œžœžœ žœžœ;žœžœ˜uJšžœžœž˜šœ˜Jšžœ ž˜Jšœ žœ˜*Jšœžœ˜&Jšœžœ˜$Jšœ žœ˜*Jšžœžœ˜J˜—šœ˜Jšžœ ž˜Jšœ žœ˜*Jšœžœ˜&Jšœžœ˜$Jšœ žœ˜*Jšžœžœ˜J˜—šœ˜J™ΓJšœF˜Fšžœžœžœ˜Jšœ0˜0Jšžœ0˜6J˜—Jšžœ ˜J˜—šœ˜Jšžœ ž˜Jšœ žœ˜&Jšœžœ˜"Jšœžœ˜ Jšœ žœ˜&Jšžœžœ˜J˜—˜Jšžœ ž˜Jšœ žœ˜(Jšœžœ˜$Jšœžœ˜"Jšœ žœ˜(Jšžœžœ˜J˜—˜Jšžœ ž˜Jšœ žœ˜&Jšœžœ˜"Jšœžœ˜ Jšœ žœ˜&Jšžœžœ˜J˜—Jšžœžœ˜J˜J˜—šŸœžœžœ žœžœ;žœžœ˜{JšœH™HJšœB™BJšœF™FJšœ?™?JšœS™SJšžœžœž˜šœ˜Jšžœ0žœžœžœ˜DJ™Jšžœ˜J˜—šœ˜J˜Jšžœ0žœžœžœ˜DJšœ,˜,šžœGžœžœž˜]Jšžœ3žœžœžœ˜G—Jšžœ˜Jšžœžœ˜J˜—šœ˜Jšœ˜Jšœ<˜