CDCellsImpl.mesa (part of ChipNDale)
Copyright © 1983, 1987 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, June 24, 1983 5:00 pm
Last Edited by: Christian Jacobi, October 16, 1987 11:57:49 am PDT
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𡤌reateEmptyCell[], 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<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 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;
};
ShowErrors:
PROC [pr:
CD.DrawRef, ob:
CD.Object, trans:
CD.Transformation] = {
WITH CDProperties.GetObjectProp[ob, $CDErrorsPrivateCell]
SELECT
FROM
ob1: CD.Object => 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𡤅 Process.Yield[]}
};
QuickDrawMeForCells: CD.DrawProc = {
cp: CD.CellSpecific = NARROW[ob.specific];
IF pr.scaleHint<cp.simplifyOn
AND pr.scaleHint>0
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.scaleHint<cp.simplifyOn
AND pr.scaleHint>0
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] = {
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];
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𡤀] = {
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.Rectox]]
};
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.Rectsics.empty] = {
Proc: CDCells.InstEnumerator = {
bbox ← CDBasics.Surround[bbox, InstRectOBound23[inst, h]];
};
[] ← EnumInsts[list, seq, Proc];
};
Init[];
END.