<> <> <> <> <> 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.