<> <> <> <> DIRECTORY CD, CDInstances, CDCells, CDCellsBackdoor, CDDirectory, CDBasics, CDBasicsInline, CDIO, CDLayers, CDOps, CDProperties, CDRects, Process USING [Yield, Detach], Properties, Real, RefTab, Rope, TerminalIO, TokenIO; CDCellsImpl: CEDAR MONITOR IMPORTS CD, CDCells, CDInstances, CDIO, CDDirectory, CDBasics, CDBasicsInline, CDLayers, CDOps, CDProperties, CDRects, Process, Properties, Real, RefTab, TerminalIO, TokenIO EXPORTS CDCells, CDCellsBackdoor SHARES CD, CDRects, CDDirectory = BEGIN cellClass: PUBLIC CD.ObjectClass = CD.RegisterObjectClass[$Cell, [ drawMe: DrawMeForCells, quickDrawMe: QuickDrawMeForCells, showMeSelected: DrawCellSelection, internalRead: ReadCell, internalWrite: WriteCell, interestRect: InterestRectCells, showsErrors: TRUE, description: "cell" ]]; pCellClass: PUBLIC CD.ObjectClass = cellClass; Init: PROC [] = { dp: REF CDDirectory.DirectoryProcs = CDDirectory.InstallDirectoryProcs[cellClass, [ enumerateChildObjects: EnumerateChildObjects, another: Another, replaceDirectChilds: ReplaceDirectChildForCell ]]; [] _ CDProperties.RegisterProperty[$InsideRect]; CDProperties.InstallProcs[prop: $InsideRect, procs: CDProperties.PropertyProcsRec[ makeCopy: CDProperties.DontCopy, internalWrite: NIL, internalRead: InternalReadProperty, exclusive: TRUE ] ]; }; IsDummyCell: PUBLIC PROC [cell: CD.Object] RETURNS [BOOL_FALSE] = { WITH cell.specific SELECT FROM cp: CD.CellSpecific => RETURN [cp.dummyCell]; ENDCASE => NULL; }; InternalReadProperty: PROC [h: TokenIO.Handle, prop: ATOM] RETURNS [val: REF] = { <<--old stuff for io format version 4>> val _ NEW[CD.Rect _ CDIO.ReadRect[h]] }; InterestRectCells: PROC [ob: CD.Object] RETURNS [CD.Rect] = { RETURN [NARROW[ob.specific, CD.CellSpecific].ir] }; EnumerateChildObjects: PROC [me: CD.Object, proc: CDDirectory.EachObjectProc, data: REF] RETURNS [quit: BOOL_FALSE] = { cp: CD.CellSpecific _ NARROW[me.specific]; FOR list: CD.InstanceList _ cp.contents, list.rest WHILE list#NIL AND ~quit DO IF proc[list.first.ob, data] THEN RETURN [quit_TRUE] ENDLOOP; IF cp.sequence#NIL THEN FOR n: NAT IN [0..cp.sequence.length) DO IF proc[cp.sequence[n].ob, data] THEN RETURN [quit_TRUE] ENDLOOP; }; Another: PROC [me: CD.Object, fromOrNil: CD.Design_NIL, into: CD.Design_NIL, friendly: BOOL_FALSE] RETURNS [new: CD.Object_CreateEmptyCell[], childAccessible: BOOL_FALSE] = { oldCp: CD.CellSpecific _ NARROW[me.specific]; newCp: CD.CellSpecific _ NARROW[new.specific]; new.bbox _ me.bbox; newCp^ _ oldCp^; newCp.dummyCell _ FALSE; [newCp.contents, newCp.sequence] _ CopyInsts[oldCp.contents, oldCp.sequence]; CDProperties.AppendProps[winner: new.properties, looser: me.properties, putOnto: new]; IF into#NIL THEN { CDDirectory.SetOwner[into, new]; IF fromOrNil=into THEN childAccessible _ TRUE; }; }; CopyInsts: PUBLIC PROC [list: CD.InstanceList, seq: CD.InstanceSequence, inPlace: BOOL_FALSE] RETURNS [lCopy: CD.InstanceList_NIL, sCopy: CD.InstanceSequence] = { <<--makes a copy of the list and the sequence, but tries to make the sequence as long as possible>> <<--inPlace TRUE: just re-use old Instances; FALSE: copy the Instances>> maxSSize: NAT = 10000; i: CD.Instance; from, to: INT _ 0; oldSLeng: INT _ IF seq=NIL THEN 0 ELSE MIN[seq.length, seq.size]; newSLeng: INT _ MIN[maxSSize, CDInstances.Length[list]+oldSLeng]; sCopy _ NEW[CD.InstanceSequenceRep[newSLeng]]; DO IF from DrawMeForCells[pr, ob1, trans, NIL]; ENDCASE => NULL; }; DrawMeForCells: CD.DrawProc = { cp: CD.CellSpecific _ NARROW[ob.specific, CD.CellSpecific]; mapClip: CD.Rect _ CDBasics.DeMapRect[pr.interestClip, trans].itemInCell; --clipping boundary in cell coordinates <<--draw border>> IF pr.borders AND cp.drawBorder THEN pr.drawOutLine[pr, CDBasicsInline.MapRect[CD.InterestRect[ob], trans], CD.outlineLayer]; <<--draw inside>> FOR w: CD.InstanceList _ cp.contents, w.rest WHILE w#NIL DO IF CDBasicsInline.IntersectRI[mapClip, w.first] THEN { IF pr.stopFlag^ THEN RETURN; pr.drawChild[pr, w.first.ob, CDBasics.ComposeTransform[w.first.trans, trans], w.first.properties]; } ENDLOOP; IF cp.sequence#NIL THEN FOR n: NAT IN [0..cp.sequence.length) DO IF CDBasicsInline.IntersectRI[mapClip, cp.sequence[n]] THEN { IF pr.stopFlag^ THEN RETURN; pr.drawChild[pr, cp.sequence[n].ob, CDBasicsInline.ComposeTransform[cp.sequence[n].trans, trans], cp.sequence[n].properties]; } ENDLOOP; IF pr.showErrors AND ob.showErrors THEN ShowErrors[pr, ob, trans]; Yield[]; }; n: INTEGER _ 8; Yield: PROC [] = INLINE { <<--we do want to yield, but not too often>> IF (n_n-1)<0 THEN {n_5; Process.Yield[]} }; QuickDrawMeForCells: CD.DrawProc = { cp: CD.CellSpecific = NARROW[ob.specific]; IF pr.scaleHint0 THEN { pr.drawOutLine[pr, CDBasics.MapRect[cp.ir, trans], CD.outlineLayer]; IF pr.scaleHint*(ob.bbox.y2-ob.bbox.y1)>9 THEN { name: Rope.ROPE ~ CDDirectory.Name[ob, pr.design]; IF name#NIL THEN pr.drawComment[pr, CDBasics.MapRect[cp.ir, trans], name]; } } ELSE { mapClip: CD.Rect _ CDBasicsInline.DeMapRect[pr.interestClip, trans]; --clipping boundary in cell coordinates <<--draw border>> IF pr.borders AND cp.drawBorder THEN pr.drawOutLine[pr, CDBasicsInline.MapRect[cp.ir, trans], CD.outlineLayer]; <<--draw inside>> FOR w: CD.InstanceList _ cp.contents, w.rest WHILE w#NIL DO IF CDBasicsInline.IntersectRI[mapClip, w.first] THEN { IF pr.stopFlag^ THEN RETURN; w.first.ob.class.quickDrawMe[pr, w.first.ob, CDBasics.ComposeTransform[w.first.trans, trans], w.first.properties]; } ENDLOOP; IF cp.sequence#NIL THEN FOR n: NAT IN [0..cp.sequence.length) DO IF CDBasicsInline.IntersectRI[mapClip, cp.sequence[n]] THEN { <<--speed up rects...>> IF pr.stopFlag^ THEN RETURN; IF cp.sequence[n].ob.class=CDRects.bareRectClass THEN pr.drawRect[pr: pr, r: CDBasicsInline.MapRect[cp.sequence[n].ob.bbox, CDBasicsInline.ComposeTransform[cp.sequence[n].trans, trans]], l: cp.sequence[n].ob.layer] ELSE cp.sequence[n].ob.class.quickDrawMe[pr, cp.sequence[n].ob, CDBasicsInline.ComposeTransform[cp.sequence[n].trans, trans], cp.sequence[n].properties]; } ENDLOOP; Yield[]; IF pr.showErrors AND ob.showErrors THEN ShowErrors[pr, ob, trans]; IF pr.checkPriority THEN pr.priorityChecker[pr]; } }; DrawCellSelection: CD.DrawProc = { cp: CD.CellSpecific ~ NARROW[ob.specific]; IF pr.scaleHint0 THEN pr.drawRect[pr, CDBasicsInline.MapRect[cp.ir, trans], CD.shadeLayer] ELSE pr.drawOutLine[pr, CDBasicsInline.MapRect[cp.ir, trans], CD.selectionLayer] }; CreateEmptyCell: PUBLIC PROC [] RETURNS [ob: CD.Object] = { ob _ NEW[CD.ObjectRep_[ class: cellClass, bbox: [0, 0, 1, 1], specific: NEW[CD.CellRep_[simplifyOn: -1]] ]]; }; CreateCell: PUBLIC PROC [il: CD.InstanceList_NIL, sq: CD.InstanceSequence_NIL, ir: CD.Rect_[0,0,-1,-1]] RETURNS [CD.Object] = { ob: CD.Object = CreateEmptyCell[]; cp: CD.CellSpecific = NARROW[ob.specific]; cp.contents _ il; cp.sequence _ sq; SetInterestRect[NIL, ob, ir, dontResize]; [] _ ResizeCell[NIL, ob]; SetSimplificationTreshhold[ob, -1]; RETURN [ob] }; CreateCellXTransformed: PUBLIC PROC [il: CD.InstanceList_NIL, sq: CD.InstanceSequence_NIL, ir: CD.Rect_[0,0,-1,-1], cTrans: CD.Transformation_[]] RETURNS [ob: CD.Object] = { <> <<[il, sq] _ CopyInsts[il, sq, FALSE, CDBasics.InverseTransform[cTrans]];>> [il, sq] _ CopyInsts[il, sq, FALSE]; FOR l: CD.InstanceList _ il, l.rest WHILE l#NIL DO l.first.trans _ CDBasics.DecomposeTransform[l.first.trans, cTrans]; ENDLOOP; IF sq#NIL THEN FOR n: NAT IN [0..sq.length) DO sq[n].trans _ CDBasics.DecomposeTransform[sq[n].trans, cTrans]; ENDLOOP; RETURN [ CreateCell[il, sq, CDBasics.DeMapRect[ir, cTrans]]]; }; ReadCell: CD.InternalReadProc = { i: INT; ob: CD.Object = CreateEmptyCell[]; specific: CD.CellSpecific = NARROW[ob.specific]; IF h.oldVersion AND CDIO.VersionKey[h]<=15 THEN { ReadCell23[ob, h]; RETURN [ob] }; specific.ir _ CDIO.ReadRect[h]; specific.simplifyOn _ TokenIO.ReadInt[h]; i _ TokenIO.ReadInt[h]; specific.specifiedIr _ (i MOD 2)#0; specific.drawBorder _ (i/2)#0; [specific.sequence, specific.contents] _ ReadInstances[h]; IF h.oldVersion AND CDIO.VersionKey[h]<17 THEN OldResize24Cell[ob] ELSE [] _ ResizeCell[NIL, ob]; IF ob.bbox.y2>ob.bbox.y1 THEN specific.simplifyOn _ specific.simplifyOn/(ob.bbox.y2-ob.bbox.y1); CDDirectory.SetOwner[CDIO.DesignInReadOperation[h], ob]; RETURN [ob]; }; ReadInstances: PUBLIC PROC [h: TokenIO.Handle] RETURNS [seq: CD.InstanceSequence, list: CD.InstanceList_NIL] = { maxSSize: NAT = 10000; num: INT = TokenIO.ReadInt[h]; newSLeng: INT _ MIN[maxSSize, num]; natNewSLeng: NAT _ newSLeng; seq _ NEW[CD.InstanceSequenceRep[natNewSLeng]]; FOR n: NAT IN [0..natNewSLeng) DO seq[n] _ CDIO.ReadInstance[h]; ENDLOOP; seq.length _ natNewSLeng; THROUGH [natNewSLeng..num) DO list _ CONS[CDIO.ReadInstance[h], list]; ENDLOOP; }; CountInstances: PUBLIC PROC [cell: CD.Object] RETURNS [n: INT_0] = { specific: CD.CellSpecific = NARROW[cell.specific]; n _ CDInstances.Length[specific.contents]; IF specific.sequence#NIL THEN n _ n+specific.sequence.length }; WriteCell: CD.InternalWriteProc = { specific: CD.CellSpecific = NARROW[ob.specific]; sLeng: NAT _ IF specific.sequence=NIL THEN 0 ELSE specific.sequence.length; i: INT _ IF specific.drawBorder THEN 2 ELSE 0; IF specific.specifiedIr THEN i _ i+1; CDIO.WriteRect[h, specific.ir]; TokenIO.WriteInt[h, Real.Round[ MAX[MIN[specific.simplifyOn, 500.0], 0.0] * MAX[MIN[(ob.bbox.y2-ob.bbox.y1), 100000], 0] ]]; TokenIO.WriteInt[h, i]; TokenIO.WriteInt[h, CountInstances[ob]]; FOR l: CD.InstanceList _ specific.contents, l.rest WHILE l#NIL DO CDIO.WriteInstance[h, l.first]; ENDLOOP; IF specific.sequence#NIL THEN FOR n: NAT IN [0..specific.sequence.length) DO CDIO.WriteInstance[h, specific.sequence[n]]; ENDLOOP; }; ReplaceDirectChildForCell: PUBLIC PROC [me: CD.Object, design: CD.Design, replace: CDDirectory.ReplaceList] RETURNS [changed: BOOL_FALSE] = { cp: CD.CellSpecific = NARROW[me.specific]; IF me.immutable THEN ERROR; FOR replaceList: CDDirectory.ReplaceList _ replace, replaceList.rest WHILE replaceList#NIL DO rep: REF CDDirectory.ReplaceRec = replaceList.first; PerInst: PROC [i: CD.Instance] = --INLINE-- { IF i.ob=rep.old THEN { changed _ TRUE; IF rep.trans#[] THEN i.trans _ CDBasics.ComposeTransform[itemInCell: rep.trans, cellInWorld: i.trans].itemInWorld; i.ob _ rep.new }; }; IF rep.old=me THEN LOOP; FOR l: CD.InstanceList _ cp.contents, l.rest WHILE l#NIL DO PerInst[l.first] ENDLOOP; IF cp.sequence#NIL THEN FOR n: NAT IN [0..cp.sequence.length) DO PerInst[cp.sequence[n]] ENDLOOP; ENDLOOP; IF changed AND ~cp.dummyCell THEN [] _ ResizeCell[design, me]; }; Bounds: PUBLIC PROC [list: CD.InstanceList_NIL, seq: CD.InstanceSequence_NIL, doIr: BOOL_TRUE, doBb: BOOL_TRUE] RETURNS [ir, bbox: CD.Rect _ CDBasics.empty] = { FOR l: LIST OF CD.Instance _ list, l.rest WHILE l#NIL DO IF doBb THEN bbox _ CDBasics.Surround[bbox, CDInstances.InstRectO[l.first]]; IF doIr AND ~CDLayers.SuppressIR[l.first.ob.layer] THEN ir _ CDBasics.Surround[ir, CDInstances.InstRectI[l.first]]; ENDLOOP; IF seq#NIL THEN FOR n: NAT IN [0..seq.length) DO IF doBb THEN bbox _ CDBasics.Surround[bbox, CDInstances.InstRectO[seq[n]]]; IF doIr AND ~CDLayers.SuppressIR[seq[n].ob.layer] THEN ir _ CDBasics.Surround[ir, CDInstances.InstRectI[seq[n]]]; ENDLOOP; }; EnumerateInstances: PUBLIC PROC [cell: CD.Object, proc: CDCells.InstEnumerator] RETURNS [quit: BOOL] = { cp: CD.CellSpecific _ NARROW[cell.specific]; quit _ EnumInsts[cp.contents, cp.sequence, proc]; }; EnumInsts: PUBLIC PROC [list: CD.InstanceList, seq: CD.InstanceSequence, proc: CDCells.InstEnumerator] RETURNS [quit: BOOL_FALSE] = { FOR l: LIST OF CD.Instance _ list, l.rest WHILE l#NIL DO IF quit THEN RETURN; quit _ proc[l.first] ENDLOOP; IF seq#NIL THEN FOR n: NAT IN [0..seq.length) DO IF quit THEN RETURN; quit _ proc[seq[n]] ENDLOOP; }; OldResize24Cell: PROC [cell: CD.Object] = { OldIBounds: PROC [list: CD.InstanceList_NIL, seq: CD.InstanceSequence_NIL] RETURNS [ir: CD.Rect _ CDBasics.empty] = { FOR l: LIST OF CD.Instance _ list, l.rest WHILE l#NIL DO ir _ CDBasics.Surround[ir, CDInstances.InstRectI[l.first]]; ENDLOOP; IF seq#NIL THEN FOR n: NAT IN [0..seq.length) DO ir _ CDBasics.Surround[ir, CDInstances.InstRectI[seq[n]]]; ENDLOOP; }; cp: CD.CellSpecific = NARROW[cell.specific]; IF ~cp.dummyCell THEN { oldBb: CD.Rect _ cell.bbox; oldIr: CD.Rect _ cp.ir; bb, ir, oir: CD.Rect; [ir, bb] _ Bounds[cp.contents, cp.sequence, ~cp.specifiedIr, TRUE]; IF cp.specifiedIr THEN ir _ cp.ir ELSE { oir _ OldIBounds[cp.contents, cp.sequence]; IF ir#oir THEN {cp.specifiedIr_TRUE; ir_oir}; }; bb _ CDBasics.Surround[bb, ir]; IF ~CDBasics.NonEmpty[bb] THEN ir _ bb _ [0, 0, 1, 1]; IF ~CDBasics.NonEmpty[ir] THEN ir _ bb; cp.ir _ ir; cell.bbox _ bb; IF cp.simplifyOn<0 THEN SetSimplificationTreshhold[cell, -1]; } }; ResizeCell: PUBLIC PROC [design: CD.Design, cell: CD.Object] RETURNS [didResize: BOOL] = { max: CD.Number = 536870910; -- LAST[CD.Number]/4-1 cp: CD.CellSpecific = NARROW[cell.specific]; IF cp.dummyCell THEN RETURN [didResize_FALSE] ELSE { oldBb: CD.Rect _ cell.bbox; oldIr: CD.Rect _ cp.ir; bb, ir: CD.Rect; [ir, bb] _ Bounds[cp.contents, cp.sequence, ~cp.specifiedIr, TRUE]; IF cp.specifiedIr THEN ir _ cp.ir; bb _ CDBasics.Surround[bb, ir]; IF ~CDBasics.NonEmpty[bb] THEN ir _ bb _ [0, 0, 1, 1]; IF ~CDBasics.NonEmpty[ir] THEN ir _ bb; IF didResize _ (ir#oldIr OR bb#oldBb) THEN { cp.ir _ ir; cell.bbox _ bb; CDDirectory.PropagateResize[design, cell] }; IF bb.x1<=-max OR bb.x2>=max OR bb.y1<=-max OR bb.y2>=max THEN TerminalIO.PutRopes["**WARNING: cell ", CD.Describe[cell, NIL, design], " too large, it might generate arithmetic overflow\n"]; IF cp.simplifyOn<0 THEN SetSimplificationTreshhold[cell, -1]; } }; IsPushedIn: PUBLIC PROC [design: CD.Design] RETURNS [yes: BOOL] = { RETURN [ design^.actual.rest#NIL ] }; <<>> IsEmpty: PUBLIC PROC [cell: CD.Object] RETURNS [BOOL_FALSE] = { cp: CD.CellSpecific _ NARROW[cell.specific]; IF cp.contents=NIL THEN RETURN [ cp.sequence=NIL OR cp.sequence.length=0 ] }; PushedCellName: PUBLIC PROC [design: CD.Design] RETURNS [Rope.ROPE] = { RETURN [SELECT TRUE FROM design=NIL => "no design", design.actual.rest=NIL => "top level", ENDCASE => design.actual.first.desc ] }; SetInterestRect: PUBLIC PROC [design: CD.Design, cell: CD.Object, r: CD.Rect _ [0, 0, -1, -1], mode: CDCells.IncludeMode] = { cp: CD.CellSpecific _ NARROW[cell.specific]; old: CD.Rect _ cp.ir; cp.specifiedIr _ CDBasics.NonEmpty[r]; IF ~cp.specifiedIr THEN { r _ Bounds[cp.contents, cp.sequence, TRUE, FALSE].ir; IF CDBasics.NonEmpty[r] THEN r _ cell.bbox; }; cp.ir _ r; SELECT mode FROM doit, dontNotify => [] _ ResizeCell[design, cell]; ENDCASE => NULL; IF mode=doit THEN CDDirectory.PropagateChange[cell, design]; }; SetBorderMode: PUBLIC PROC [cell: CD.Object, draw: BOOL] = { WITH cell.specific SELECT FROM cp: CD.CellSpecific => cp.drawBorder _ draw ENDCASE => NULL; }; SetSimplificationTreshhold: PUBLIC PROC [cell: CD.Object, val: REAL, inPixels: BOOL_TRUE] = { WITH cell.specific SELECT FROM cp: CD.CellSpecific => cp.simplifyOn _ IF val<0 THEN 100.0/MAX[(cell.bbox.y2-cell.bbox.y1)+(cell.bbox.x2-cell.bbox.x1), 2] ELSE IF inPixels THEN val/MAX[(cell.bbox.y2-cell.bbox.y1), 1] ELSE val; ENDCASE => NULL; }; ToSequenceMode: PUBLIC PROC [cell: CD.Object] = { IF CDCells.IsCell[cell] AND ~IsDummyCell[cell] THEN { cp: CD.CellSpecific _ NARROW[cell.specific]; [cp.contents, cp.sequence] _ CopyInsts[cp.contents, cp.sequence, TRUE] } }; -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- IncludeInstance: PUBLIC PROC [design: CD.Design _ NIL, cell: CD.Object _ NIL, inst: CD.Instance, mode: CDCells.IncludeMode] RETURNS [resize: BOOL] = { cp: CD.CellSpecific; IF inst=NIL OR inst.ob=NIL THEN ERROR CD.Error[calling, "Include NIL inst"]; IF cell#NIL THEN cp _ NARROW[cell.specific] ELSE IF design#NIL THEN cp _ design^.actual.first.specific ELSE ERROR; IF cell=NIL THEN cp.contents _ CONS[inst, cp.contents] --does not yet change insideRect !! ELSE { IF cell.immutable THEN ERROR; cp.contents _ CONS[inst, cp.contents]; --does not yet change insideRect !! resize _ ~CDBasics.Inside[CDInstances.InstRectO[inst], cell.bbox]; IF ~resize AND ~cp.specifiedIr THEN resize _ ~CDBasics.Inside[CDInstances.InstRectI[inst], cp.ir]; IF resize THEN SELECT mode FROM doit, dontNotify => [] _ ResizeCell[design, cell]; ENDCASE => NULL; IF mode=doit THEN CDDirectory.PropagateChange[cell, design]; }; IF design#NIL AND mode=doit THEN { IF cp.dummyCell THEN CDOps.RedrawInstance[design, inst, FALSE] ELSE CDOps.Redraw[design] }; }; IncludeOb: PUBLIC PROC [design: CD.Design, cell: CD.Object, ob: CD.Object, trans: CD.Transformation, mode: CDCells.IncludeMode] RETURNS [newInst: CD.Instance_NIL, resize: BOOL_FALSE] = { newInst _ NEW[CD.InstanceRep _ [ob: ob, trans: trans]]; resize _ IncludeInstance[design, cell, newInst, mode]; }; RemoveN: ENTRY PROC [seq: CD.InstanceSequence, n: INT] = { <<--be conservative; make sure no nil instances are introduced by bad client concurrency>> ENABLE UNWIND => NULL; IF seq#NIL THEN { leng: NAT _ seq.length; IF leng>seq.size THEN { leng _ seq.length _ seq.size; TRUSTED {Process.Detach[FORK TerminalIO.PutRope["**unconsistant instance sequence found/n"]]}; }; IF n>=leng OR leng=0 THEN RETURN; seq[n] _ seq[leng-1]; seq.length _ leng-1; seq[leng-1] _ NIL; } }; RemoveInstance: PUBLIC PROC [design: CD.Design _ NIL, cell: CD.Object, inst: CD.Instance, mode: CDCells.IncludeMode] RETURNS [resize: BOOL] = { cp: CD.CellSpecific; done: BOOL _ FALSE; IF cell=NIL THEN { IF design=NIL THEN ERROR CD.Error[calling, "Remove from NIL cell"]; cp _ design^.actual.first.specific; } ELSE { IF cell.immutable THEN ERROR; cp _ NARROW[cell.specific]; }; IF cp.contents#NIL THEN { IF cp.contents.first=inst THEN {cp.contents _ cp.contents.rest; done _ TRUE} ELSE FOR list: CD.InstanceList _ cp.contents, list.rest WHILE list.rest#NIL DO IF list.rest.first=inst THEN {list.rest _ list.rest.rest; done _ TRUE; EXIT} ENDLOOP; }; IF ~done AND cp.sequence#NIL THEN FOR n: NAT IN [0..cp.sequence.length) DO IF cp.sequence[n]=inst THEN { RemoveN[cp.sequence, n]; done _ TRUE; EXIT } ENDLOOP; IF cell#NIL THEN { oldr: CD.Rect _ CDBasics.Surround[cell.bbox, cp.ir]; r: CD.Rect = CDInstances.InstRectO[inst]; resize _ r.x1<=oldr.x1 OR r.y1<=oldr.y1 OR r.x2>=oldr.x2 OR r.y2>=oldr.y2; IF ~resize AND ~cp.specifiedIr THEN { r: CD.Rect = CDInstances.InstRectI[inst]; resize _ r.x1<=cp.ir.x1 OR r.y1<=cp.ir.y1 OR r.x2>=cp.ir.x2 OR r.y2>=cp.ir.y2; }; IF resize THEN SELECT mode FROM doit, dontNotify => [] _ ResizeCell[design, cell]; ENDCASE => NULL; IF mode=doit THEN CDDirectory.PropagateChange[cell, design]; }; IF design#NIL AND mode=doit THEN { IF cp.dummyCell THEN CDOps.RedrawInstance[design, inst] ELSE CDOps.Redraw[design] }; }; <<--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>> Get23Table: PROC [h: TokenIO.Handle] RETURNS [RefTab.Ref_NIL] = { rt: RefTab.Ref; WITH Properties.GetProp[h.properties^, $convert23] SELECT FROM tab: RefTab.Ref => rt _ tab; ENDCASE => { rt _ RefTab.Create[201]; h.properties^ _ Properties.PutProp[h.properties^, $convert23, rt] }; RETURN [rt]; }; ReadCell23: PROC [ob: CD.Object, h: TokenIO.Handle] = { <<--old file format versions>> i: INT; origin: CD.Position; oldBbox: CD.Rect; bb1: CD.Rect; specific: CD.CellSpecific = NARROW[ob.specific]; size: CD.Position _ CDIO.ReadPos[h]; IF CDIO.VersionKey[h]>=8 THEN { --not that old specific.simplifyOn _ TokenIO.ReadInt[h]; i _ TokenIO.ReadInt[h]; specific.specifiedIr _ (i MOD 2)#0; specific.drawBorder _ (i/2)#0; IF specific.specifiedIr THEN specific.ir _ CDIO.ReadRect[h]; origin _ CDIO.ReadPos[h]; } ELSE { -- very old versions IF CDIO.VersionKey[h]<1 THEN { [--name--] _ TokenIO.ReadRope[h]; } ELSE { specific.simplifyOn _ TokenIO.ReadInt[h]; }; }; [specific.sequence, specific.contents] _ ReadInstances[h]; oldBbox _ CDBasics.RectAt[[0, 0], size]; bb1 _ BoundsSL23[specific.sequence, specific.contents, h]; IF bb1#oldBbox THEN { TerminalIO.PutRope["conversion problem; check design carefully\n"]; }; [] _ ResizeCell[NIL, ob]; IF oldBbox#ob.bbox THEN PutBox23[ob, h, oldBbox]; IF ob.bbox.y2>ob.bbox.y1 THEN specific.simplifyOn _ specific.simplifyOn/(ob.bbox.y2-ob.bbox.y1); }; PutBox23: PROC [ob: CD.Object, h: TokenIO.Handle, bbox: CD.Rect] = { tab: RefTab.Ref _ Get23Table[h]; [] _ RefTab.Insert[tab, ob, NEW[CD.Rect_bbox]] }; BBox23: PROC [ob: CD.Object, h: TokenIO.Handle] RETURNS [bbox: CD.Rect] = { bbox_ob.bbox; IF ob.class.composed THEN <<--it doesn't work with properties, they aren't yet initialized>> WITH RefTab.Fetch[Get23Table[h], ob].val SELECT FROM rr: REF CD.Rect => RETURN [rr^] ENDCASE => NULL; }; InstRectOBound23: PROC [inst: CD.Instance, h: TokenIO.Handle] RETURNS [CD.Rect] = { RETURN [CDBasics.MapRect[BBox23[inst.ob, h], inst.trans]] }; BoundsSL23: PROC [seq: CD.InstanceSequence_NIL, list: CD.InstanceList_NIL, h: TokenIO.Handle] RETURNS [bbox: CD.Rect_CDBasics.empty] = { Proc: CDCells.InstEnumerator = { bbox _ CDBasics.Surround[bbox, InstRectOBound23[inst, h]]; }; [] _ EnumInsts[list, seq, Proc]; }; Init[]; END.