<> <> <> <> <<>> 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; <> <> <<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.>> <> <<>> 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]; < DeselectTraj[traj, 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; }; <> <