DIRECTORY CD, CDBasics, CDCells, CDDefaultProcs, CDDirectory, CDEvents, CDInstances, CDProperties, GList, HashTable, IO, PWObjects, Rope, TerminalIO; PWObjectsImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDDefaultProcs, CDDirectory, CDEvents, CDInstances, CDProperties, GList, HashTable, IO, Rope, TerminalIO EXPORTS PWObjects SHARES CDDirectory = BEGIN OPEN PWObjects; ROPE: TYPE = Rope.ROPE; ROPES: TYPE = LIST OF ROPE; abutXClass: PUBLIC CD.ObjectClass _ RegisterClass[objectType: $AbutX, expand: ExpandAbut, enumerateChildObjects: EnumerateChildObjectsAbut, replaceDirectChilds: ReplaceDirectChildsAbut, interestRect: AbutInterestRect]; abutYClass: PUBLIC CD.ObjectClass _ RegisterClass[objectType: $AbutY, expand: ExpandAbut, enumerateChildObjects: EnumerateChildObjectsAbut, replaceDirectChilds: ReplaceDirectChildsAbut, interestRect: AbutInterestRect]; AbutSpecific: TYPE = REF AbutSpecificRec; AbutSpecificRec: TYPE = RECORD [ ir: CD.Rect, -- for algorithmic efficiency subObjects: SEQUENCE size: NAT OF CD.Object ]; CreateNewAbutX: PUBLIC CreateAbutProc = { abutSpecific: AbutSpecific _ NEW [AbutSpecificRec[GList.Length[subObjects]]]; new: CD.Object; FOR i: NAT IN [0 .. abutSpecific.size) DO abutSpecific[i] _ subObjects.first; subObjects _ subObjects.rest; ENDLOOP; newAbut _ NEW [CD.ObjectRep _ [class: abutXClass, specific: abutSpecific]]; new _ ExpandAbut[newAbut, NIL, NIL].new; newAbut.bbox _ new.bbox; abutSpecific.ir _ CD.InterestRect[new]; }; CreateNewAbutY: PUBLIC CreateAbutProc = { abutSpecific: AbutSpecific _ NEW [AbutSpecificRec[GList.Length[subObjects]]]; new: CD.Object; FOR i: NAT IN [0 .. abutSpecific.size) DO abutSpecific[i] _ subObjects.first; subObjects _ subObjects.rest; ENDLOOP; newAbut _ NEW [CD.ObjectRep _ [class: abutYClass, specific: abutSpecific]]; new _ ExpandAbut[newAbut, NIL, NIL].new; newAbut.bbox _ new.bbox; abutSpecific.ir _ CD.InterestRect[new]; }; EnumerateSubObjects: PUBLIC PROC [abut: CD.Object, eachSubObject: EachSubObjectProc] = { abutSpecific: AbutSpecific = NARROW [abut.specific]; pos: CD.Position _ [0, 0]; FOR i: NAT IN [0 .. abutSpecific.size) DO eachSubObject[abutSpecific[i], pos]; SELECT abut.class FROM abutXClass => pos.x _ pos.x + CD.InterestSize[abutSpecific[i]].x; abutYClass => pos.y _ pos.y + CD.InterestSize[abutSpecific[i]].y; ENDCASE => ERROR; ENDLOOP; }; ExpandAbut: CDDirectory.ExpandProc = { EachSubObject: EachSubObjectProc = { instances _ CONS [CDInstances.NewInst[subObject, [CDBasics.SubPoints[pos, CD.InterestBase[subObject]]]], instances]; }; instances: LIST OF CD.Instance; EnumerateSubObjects[me, EachSubObject]; new _ CreateCell[instances: instances, name: Rope.Cat[CDDirectory.Name[me], "-AbutExpanded"]]; IF into#NIL THEN [] _ CDDirectory.Include[into, new]; }; EnumerateChildObjectsAbut: CDDirectory.EnumerateChildObjectsProc = { EachSubObject: EachSubObjectProc = {p[subObject, x]}; EnumerateSubObjects[me, EachSubObject]; }; ReplaceDirectChildsAbut: CDDirectory.ReplaceDChildsProc = { EachSubObject: EachSubObjectProc = { FOR l: CDDirectory.ReplaceList _ replace, l.rest WHILE l#NIL DO IF l.first.old=subObject THEN {changed _ TRUE; EXIT}; ENDLOOP; }; bbox: CD.Rect _ me.bbox; EnumerateSubObjects[me, EachSubObject]; IF ~changed THEN RETURN; me.bbox _ ExpandAbut[me, NIL, NIL].new.bbox; changed _ bbox = me.bbox; CDDirectory.PropagateResize[design, me]; }; AbutInterestRect: CD.RectProc = { abutSpecific: AbutSpecific = NARROW [ob.specific]; RETURN [abutSpecific.ir]; }; routingClass: PUBLIC CD.ObjectClass _ RegisterClass[objectType: $Routing, expand: ExpandRouting, interestRect: RoutingInterestRect]; ExpandRouting: CDDirectory.ExpandProc = { routingSpecific: RoutingSpecific = NARROW [me.specific]; instances: LIST OF CD.Instance _ NIL; FOR i: NAT IN [0 .. routingSpecific.size) DO node: Node _ routingSpecific[i]; FOR j: NAT IN [0 .. node.size) DO instances _ CONS [ CDInstances.NewInst[ node[j].object, [CDBasics.SubPoints[node[j].position, CD.InterestBase[node[j].object]]], CDProperties.DCopyProps[node.properties] ], instances]; ENDLOOP; ENDLOOP; new _ CreateCell[instances: instances, ir: routingSpecific.ir, name: Rope.Cat[CDDirectory.Name[me], "-RoutingExpanded"]]; IF CD.InterestRect[new]#routingSpecific.ir THEN ERROR; -- CD Broken! }; CreateRouting: PUBLIC PROC [ir: CD.Rect, nodes: LIST OF Node] RETURNS [routing: CD.Object] = { size: NAT = NAT [GList.Length[nodes]]; routingSpecific: RoutingSpecific = NEW [RoutingRep[size]]; FOR i: NAT IN [0 .. size) DO routingSpecific[i] _ nodes.first; nodes _ nodes.rest ENDLOOP; routingSpecific.ir _ ir; routing _ NEW [CD.ObjectRep _ [class: routingClass, bbox: [0, 0, 0, 0], specific: routingSpecific]]; routing.bbox _ ExpandRouting[routing, NIL, NIL].new.bbox; }; CreateNode: PUBLIC PROC [geometry: LIST OF PlacedObject, properties: CD.PropList _ NIL] RETURNS [node: Node] = { size: NAT _ 0; FOR list: LIST OF PlacedObject _ geometry, list.rest WHILE list#NIL DO size _ size + 1 ENDLOOP; node _ NEW [NodeRep[size]]; node.properties _ properties; FOR i: NAT IN [0 .. size) DO node[i] _ geometry.first; geometry _ geometry.rest ENDLOOP; }; CreateNodes: PUBLIC PROC [table: HashTable.Table] RETURNS [nodes: LIST OF Node _ NIL] = { EachPair: HashTable.EachPairAction = { name: Rope.ROPE = NARROW [key]; geometry: REF LIST OF PlacedObject = NARROW [value]; node: Node = CreateNode[geometry^, LIST [[key: $SignalName, val: name]]]; nodes _ CONS [node, nodes]; }; [] _ HashTable.Pairs[table, EachPair]; }; RoutingInterestRect: CD.RectProc = { routingSpecific: RoutingSpecific = NARROW [ob.specific]; RETURN [routingSpecific.ir]; }; indirectClass: PUBLIC CD.ObjectClass _ RegisterClass[objectType: $Indirect, expand: ExpandIndirect, replaceDirectChilds: ReplaceDirectChildsIndirect]; CreateIndirect: PUBLIC PROC [sourceObject: CD.Object] RETURNS [indirectObject: CD.Object] = { IF sourceObject=NIL THEN RETURN [NIL]; indirectObject _ NEW [CD.ObjectRep _ [class: indirectClass, bbox: sourceObject.bbox, specific: sourceObject]]; }; ExpandIndirect: CDDirectory.ExpandProc = {new _ NARROW [me.specific]}; ReplaceDirectChildsIndirect: CDDirectory.ReplaceDChildsProc = { indirect: CD.Object = NARROW [me.specific]; bbox: CD.Rect _ me.bbox; FOR l: CDDirectory.ReplaceList _ replace, l.rest WHILE l#NIL DO IF l.first.old=indirect THEN {changed _ TRUE; EXIT}; ENDLOOP; IF ~changed THEN RETURN; me.bbox _ indirect.bbox; changed _ bbox = me.bbox; CDDirectory.PropagateResize[design, me]; }; lazyClass: PUBLIC CD.ObjectClass _ RegisterClass[objectType: $Lazy, expand: ExpandLazy, interestRect: LazyIR]; LazyData: TYPE = REF LazyDataRec; LazyDataRec: TYPE = RECORD [info: REF, createProc: CreateProc, ir: CD.Rect]; CreateLazy: PUBLIC PROC [info: REF, createProc: CreateProc, bbox, ir: CD.Rect] RETURNS [newLazy: CD.Object] = { newLazy _ NEW [CD.ObjectRep _ [class: lazyClass, specific: NEW [LazyDataRec _ [info: info, createProc: createProc, ir: ir]]]]; newLazy.bbox _ bbox; }; LazyIR: CD.RectProc = {lazyData: LazyData _ NARROW [ob.specific]; RETURN [lazyData.ir]}; ExpandLazy: CDDirectory.ExpandProc = { lazyData: LazyData _ NARROW [me.specific]; new _ lazyData.createProc[lazyData.info]; IF CD.InterestRect[new]#lazyData.ir OR new.bbox#me.bbox THEN ERROR; IF into#NIL THEN [] _ CDDirectory.Include[into, new]; }; CreateCell: PUBLIC PROC [instances: CD.InstanceList, ir: CD.Rect _ [0,0,-1,-1], name: ROPE _ NIL, properties: CD.PropList _ NIL] RETURNS [cell: CD.Object]= { cell _ CDCells.CreateCell[il: instances, ir: ir]; CDCells.ToSequenceMode[cell]; WHILE properties#NIL DO CDProperties.PutObjectProp[cell, properties.first.key, properties.first.val]; properties _ properties.rest; ENDLOOP; IF name#NIL THEN { cellSpecific: CD.CellSpecific _ NARROW [cell.specific]; cellSpecific.name _ name; }; }; propertiesToFlushOnEdit: LIST OF ATOM _ NIL; childToParents: HashTable.Table _ HashTable.Create[]; AddChildParent: PROC [child, parent: CD.Object] = { parents: LIST OF CD.Object _ NARROW [HashTable.Fetch[childToParents, child].value]; IF GList.Member[parent, parents] THEN RETURN; parents _ CONS [parent, parents]; [] _ HashTable.Store[childToParents, child, parents]; }; FlushPropertiesAfterReplace: CDEvents.EventProc = { BuildTable: CDDirectory.EachEntryAction = { EachChild: CDDirectory.EnumerateObjectsProc = {AddChildParent[me, ob]}; sch: ROPE _ NARROW [CDProperties.GetObjectProp[ob, $IconFor]]; schOb: CD.Object _ IF sch#NIL THEN CDDirectory.Fetch[design, sch].object ELSE NIL; IF schOb#NIL THEN AddChildParent[schOb, ob]; schOb _ IF Rope.Match["*.mask", name] THEN CDDirectory.Fetch[design, Rope.Replace[base: name, start: Rope.Length[name]-4, with: "sch"]].object ELSE NIL; IF schOb#NIL THEN AddChildParent[ob, schOb]; CDDirectory.EnumerateChildObjects[ob, EachChild]; }; changedObjects: LIST OF CD.Object _ LIST [NARROW [x]]; foundANewOne: BOOL _ TRUE; flushedObjects: ROPE _ NIL; [] _ CDDirectory.Enumerate[design, BuildTable]; WHILE foundANewOne DO foundANewOne _ FALSE; FOR list: LIST OF CD.Object _ changedObjects, list.rest WHILE list#NIL DO FOR parents: LIST OF CD.Object _ NARROW [HashTable.Fetch[childToParents, list.first].value], parents.rest WHILE parents#NIL DO IF GList.Member[parents.first, changedObjects] THEN LOOP; changedObjects _ CONS [parents.first, changedObjects]; foundANewOne _ TRUE; ENDLOOP; ENDLOOP; ENDLOOP; FOR list: LIST OF CD.Object _ changedObjects, list.rest WHILE list#NIL DO flushed: BOOL _ FALSE; FOR props: LIST OF ATOM _ propertiesToFlushOnEdit, props.rest WHILE props#NIL DO IF CDProperties.GetObjectProp[list.first, props.first]=NIL THEN LOOP; flushed _ TRUE; CDProperties.PutObjectProp[list.first, props.first, NIL]; ENDLOOP; IF flushed THEN flushedObjects _ Rope.Cat[flushedObjects, " ", CDDirectory.Name[list.first]]; ENDLOOP; IF flushedObjects#NIL THEN TerminalIO.PutF["Flushed caches for %g.\n ", IO.rope[flushedObjects]]; HashTable.Erase[childToParents]; -- we clean up that table! }; RegisterProp: PUBLIC PROC [prop: ATOM, copy: BOOL _ FALSE, flushOnEdit: BOOL _ FALSE] RETURNS [sameAtom: ATOM] = { [] _ CDProperties.RegisterProperty[prop, $PW]; CDProperties.InstallProcs[prop, [makeCopy: IF copy THEN CDProperties.CopyVal ELSE CDProperties.DontCopy]]; IF flushOnEdit THEN propertiesToFlushOnEdit _ CONS [prop, propertiesToFlushOnEdit]; sameAtom _ prop; }; RegisterClass: PUBLIC PROC [objectType: ATOM, expand: CDDirectory.ExpandProc, enumerateChildObjects: CDDirectory.EnumerateChildObjectsProc _ NIL, replaceDirectChilds: CDDirectory.ReplaceDChildsProc _ NIL, interestRect: CD.RectProc _ NIL, drawMe, quickDrawMe, showMeSelected: CD.DrawProc _ NIL] RETURNS [objectClass: CD.ObjectClass] = { dp: CDDirectory.DirectoryProcs _ [expand: expand]; objectClassRec: CD.ObjectClassRec _ []; objectClassRec.showMeSelected _ CDDefaultProcs.ShowMeSelectedWithExpand; objectClassRec.interestRect _ IF interestRect=NIL THEN CDDefaultProcs.InterestRectWithExpand ELSE interestRect; objectClassRec.drawMe _ IF interestRect=NIL THEN CDDefaultProcs.DrawMe ELSE drawMe; objectClassRec.quickDrawMe _ IF interestRect=NIL THEN CDDefaultProcs.QuickDrawMe ELSE quickDrawMe; objectClassRec.showMeSelected _ IF interestRect=NIL THEN CDDefaultProcs.ShowMeSelected ELSE showMeSelected; objectClassRec.directoryProcs _ NIL; objectClassRec.inDirectory _ FALSE; IF enumerateChildObjects#NIL THEN dp.enumerateChildObjects _ enumerateChildObjects; IF replaceDirectChilds#NIL THEN dp.replaceDirectChilds _ replaceDirectChilds; objectClass _ CD.RegisterObjectClass[objectType, objectClassRec ! CD.Error => CONTINUE]; IF objectClass=NIL THEN objectClass _ CD.FetchObjectClass[objectType]; objectClass.directoryProcs _ CDDirectory.InstallDirectoryProcs[objectClass, dp ! CD.Error => CONTINUE]; }; CDEvents.RegisterEventProc[$AfterCellReplacement, FlushPropertiesAfterReplace]; END. PWObjectsImpl.mesa Copyright c 1984, 1985, 1986 by Xerox Corporation. All rights reversed. Created by Bertrand Serlet, February 3, 1985 12:49:51 pm PST Last edited by Bertrand Serlet, March 17, 1987 11:36:31 pm PST TO DO: DrawProcs Abuts Takes an abut and returns the cell which is equivalent to this abut. Cell resulting always belongs to the from design if me belongs to the from design. It is included in the to design if to#NIL Routing Cells Indirect In the future, add an IR proc, and maybe a Draw Proc? Lazy Implementors goodies Mechanism for flushing during edits Having a HashTable (of the right size) helps avoiding frequent allocations. we include icons of sch In case ob is a mask, the corresponding sch (if any) "depends" on it. That's a hack! We add all the children Κt˜šœ™Jšœ Οmœ=™HJšœ9Οk™˜GJšœžœžœ,˜>Jš œžœ žœžœžœ'žœžœ˜RJšœ™Jšžœžœžœ˜,JšœU™UJš œžœžœežœžœ˜˜Jšžœžœžœ˜,Jšœ™Jšœ1˜1Jšœ˜—Jš œžœžœžœ žœžœ˜6J–< -- [name: ROPE, ob: CD.Object] RETURNS [quit: BOOL _ FALSE]šœžœžœ˜Jšœžœžœ˜Jšœ0˜0šžœžœ˜Jšœžœ˜š žœžœžœžœ$žœžœž˜Išžœ žœžœžœ žœCžœ žœž˜~Jšžœ-žœžœ˜9Jšœžœ1žœ˜KJšžœ˜—Jšžœ˜—Jšžœ˜—š žœžœžœžœ$žœžœž˜IJšœ žœžœ˜š žœžœžœžœ'žœžœž˜PJšžœ5žœžœžœ˜EJšœ žœ˜Jšœ4žœ˜:Jšžœ˜—Jšžœ žœN˜]Jšžœ˜—Jšžœžœžœ.žœ˜aJšœ!’˜;Jšœ˜J˜—š£ œžœžœžœžœžœžœžœžœ žœ˜rJšœ.˜.Jšœ+žœžœžœ˜jJšžœ žœžœ!˜SJšœ˜J˜J˜—š£ œžœžœžœažœ8žœžœ žœ'žœ žœžœžœ˜ΟLšœ2˜2Lšœžœ˜'LšœH˜HJš œžœžœžœ'žœ˜oJš œžœžœžœžœ˜SJš œžœžœžœžœ ˜bJš œ žœžœžœžœ˜kLšœ žœžœ˜HLšžœžœžœ2˜SLšžœžœžœ.˜MLšœžœ2žœ žœ˜XLšžœ žœžœžœ˜FLšœQžœ žœ˜gL˜L˜—JšœO˜OL˜—Jšžœ˜—…—. Aš