CDCellsImpl.mesa (part of ChipNDale)
Copyright © 1983, 1986 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, June 24, 1983 5:00 pm
Last Edited by: Christian Jacobi, January 10, 1987 11:49:00 am PST
DIRECTORY
CD,
CDInstances,
CDCells,
CDCellsBackdoor,
CDDirectory,
CDBasics,
CDBasicsInline,
CDIO,
CDOps,
CDProperties,
CDRects,
Process USING [Yield, Detach],
PropertyLists,
Real,
RefTab,
Rope,
TerminalIO,
TokenIO;
CDCellsImpl: CEDAR MONITOR
IMPORTS CD, CDCells, CDInstances, CDIO, CDDirectory, CDBasics, CDBasicsInline, CDOps, CDProperties, CDRects, Process, PropertyLists, Real, RefTab, Rope, 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,
describe: Describe,
interestRect: InterestRectCells
]];
pCellClass: PUBLIC CD.ObjectClass = cellClass;
Init: PROC [] = {
dp: REF CDDirectory.DirectoryProcs = CDDirectory.InstallDirectoryProcs[cellClass, [
enumerateChildObjects: EnumerateChildObjects,
name: Name,
directoryOp: DirectoryOp,
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 [BOOLFALSE] = {
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]
};
DirectoryOp: PROC [me: CD.Object, design: CD.Design, name: Rope.ROPE, function: CDDirectory.DirectoryFunction] RETURNS [proceed: BOOLTRUE] = {
IF function#remove THEN
NARROW[me.specific, CD.CellSpecific].name ← name
};
Name: PROC [me: CD.Object] RETURNS [Rope.ROPE] = {
RETURN [NARROW[me.specific, CD.CellSpecific].name]
};
EnumerateChildObjects: PROC [me: CD.Object, p: CDDirectory.EnumerateObjectsProc, x: REF] = {
cp: CD.CellSpecific ← NARROW[me.specific];
FOR list: CD.InstanceList ← cp.contents, list.rest WHILE list#NIL DO
p[list.first.ob, x]
ENDLOOP;
IF cp.sequence#NIL THEN
FOR n: NAT IN [0..cp.sequence.length) DO p[cp.sequence[n].ob, x] ENDLOOP;
};
Another: PROC [me: CD.Object, fromOrNil: CD.Design, into: CD.Design, friendly: BOOL] RETURNS [
new: CD.Object ← CreateEmptyCell[],
topMode: CDDirectory.InclOrReady ← ready,
childMode: CDDirectory.ImmOrIncl ← immutable] = {
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 fromOrNil=into AND into#NIL THEN childMode ← included
};
CopyInsts: PUBLIC PROC [list: CD.InstanceList, seq: CD.InstanceSequence, inPlace: BOOLFALSE] 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 reuse old Instances; FALSE: copy the Instances
maxSSize: NAT = 10000;
i: CD.Instance;
from, to: INT ← 0;
oldSLeng: INTIF seq=NIL THEN 0 ELSE MIN[seq.length, seq.size];
newSLeng: INTMIN[maxSSize, CDInstances.Length[list]+oldSLeng];
sCopy ← NEW[CD.InstanceSequenceRep[newSLeng]];
DO
IF from<oldSLeng THEN {i ← seq[from]; from ← from+1}
ELSE IF list#NIL THEN {i ← list.first; list ← list.rest}
ELSE EXIT;
IF i#NIL AND i.ob#NIL THEN {
IF ~inPlace THEN i ← CDInstances.Copy[i];
IF trans#[] THEN i.trans ← CDBasicsInline.ComposeTransform[i.trans, trans];
IF to<newSLeng THEN {sCopy[to] ← i; to ← to+1}
ELSE IF inPlace THEN {lCopy ← CONS[i, list]; EXIT}
ELSE lCopy ← CONS[i, lCopy];
};
ENDLOOP;
sCopy.length ← to;
};
DrawMeForCells: PROC [inst: CD.Instance, trans: CD.Transformation, pr: CD.DrawRef] = {
cp: CD.CellSpecific ← NARROW[inst.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[CDBasicsInline.MapRect[CD.InterestRect[inst.ob], trans], CD.outlineLayer, pr];
--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[w.first, CDBasics.ComposeTransform[w.first.trans, trans], pr];
}
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[cp.sequence[n], CDBasicsInline.ComposeTransform[cp.sequence[n].trans, trans], pr];
}
ENDLOOP;
Yield[];
};
n: INTEGER ← 8;
Yield: PROC [] = INLINE {
--we do want to yield, but not too often
IF (n←n-1)<0 THEN {n𡤅 Process.Yield[]}
};
QuickDrawMeForCells: PROC [inst: CD.Instance, trans: CD.Transformation, pr: CD.DrawRef] = {
cp: CD.CellSpecific = NARROW[inst.ob.specific];
IF pr.scaleHint<cp.simplifyOn AND pr.scaleHint>0 THEN {
pr.drawOutLine[CDBasics.MapRect[cp.ir, trans], CD.outlineLayer,pr];
IF pr.scaleHint*(inst.ob.bbox.y2-inst.ob.bbox.y1)>9 THEN
pr.drawComment[CDBasics.MapRect[cp.ir, trans], cp.name, pr];
}
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[CDBasicsInline.MapRect[cp.ir, trans], CD.outlineLayer, pr];
--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[w.first, CDBasics.ComposeTransform[w.first.trans, trans], pr];
}
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[CDBasicsInline.MapRect[cp.sequence[n].ob.bbox, CDBasicsInline.ComposeTransform[cp.sequence[n].trans, trans]], cp.sequence[n].ob.layer, pr]
ELSE
cp.sequence[n].ob.class.quickDrawMe[cp.sequence[n], CDBasicsInline.ComposeTransform[cp.sequence[n].trans, trans], pr];
}
ENDLOOP;
Yield[];
IF pr.checkPriority THEN pr.priorityChecker[pr];
}
};
DrawCellSelection: PROC [inst: CD.Instance, trans: CD.Transformation, pr: CD.DrawRef] = {
cp: CD.CellSpecific ~ NARROW[inst.ob.specific];
IF pr.scaleHint<cp.simplifyOn AND pr.scaleHint>0 THEN
pr.drawRect[CDBasicsInline.MapRect[cp.ir, trans], CD.shadeLayer, pr]
ELSE
pr.drawOutLine[CDBasicsInline.MapRect[cp.ir, trans], CD.selectionLayer, pr]
};
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] = {
RETURN [ CreateCell[CDInstances.DeComposedList[il, cTrans], CDBasics.DeMapRect[ir, cTrans]] ]
[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];
[] ← ResizeCell[NIL, ob];
IF ob.bbox.y2>ob.bbox.y1 THEN
specific.simplifyOn ← specific.simplifyOn/(ob.bbox.y2-ob.bbox.y1);
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: INTMIN[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𡤀] = {
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: NATIF specific.sequence=NIL THEN 0 ELSE specific.sequence.length;
i: INTIF 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;
};
Describe: PROC[ob: CD.Object] RETURNS [Rope.ROPE] = {
RETURN [Rope.Concat["cell ", NARROW[ob.specific, CD.CellSpecific].name]]
};
ReplaceDirectChildForCell: PUBLIC PROC [me: CD.Object, design: CD.Design, replace: CDDirectory.ReplaceList] RETURNS [changed: BOOLFALSE] = {
cp: CD.CellSpecific = NARROW[me.specific];
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: BOOLTRUE, doBb: BOOLTRUE] 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 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 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: BOOLFALSE] = {
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;
};
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 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 ", cp.name, " 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 [BOOLFALSE] = {
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.specific.name
]
};
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;
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: BOOLTRUE] = {
WITH cell.specific SELECT FROM
cp: CD.CellSpecific => cp.simplifyOn ←
IF val<0 THEN 50.0/MAX[(cell.bbox.y2-cell.bbox.y1), 1]
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[callingError, "Include NIL inst"];
IF cell#NIL THEN cp ← NARROW[cell.specific]
ELSE IF design#NIL THEN cp ← design^.actual.first.specific
ELSE ERROR;
cp.contents ← CONS[inst, cp.contents]; --does not yet change insideRect !!
IF cell#NIL THEN {
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 cell=NIL 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: BOOLFALSE] = {
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: BOOLFALSE;
IF cell=NIL THEN {
IF design=NIL THEN ERROR CD.Error[callingError, "Remove from NIL cell"];
cp ← design^.actual.first.specific;
}
ELSE 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 cell=NIL THEN CDOps.RedrawInstance[design, inst]
ELSE CDOps.Redraw[design]
};
};
--xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Get23Table: PROC [h: TokenIO.Handle] RETURNS [RefTab.Ref←NIL] = {
rt: RefTab.Ref;
WITH PropertyLists.GetProp[h.properties^, $convert23] SELECT FROM
tab: RefTab.Ref => rt ← tab;
ENDCASE => {
rt ← RefTab.Create[201];
h.properties^ ← PropertyLists.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;
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 {
specific.name ← TokenIO.ReadRope[h];
}
ELSE {
specific.simplifyOn ← TokenIO.ReadInt[h];
};
};
[specific.sequence, specific.contents] ← ReadInstances[h];
oldBbox ← BoundsSL23[specific.sequence, specific.contents, h];
[] ← 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�ox]]
};
BBox23: PROC [ob: CD.Object, h: TokenIO.Handle] RETURNS [bbox: CD.Rect] = {
bbox←ob.bbox;
IF ob.class.inDirectory 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�sics.empty] = {
Proc: CDCells.InstEnumerator = {
bbox ← CDBasics.Surround[bbox, InstRectOBound23[inst, h]];
};
[] ← EnumInsts[list, seq, Proc];
};
Init[];
END.